
#include "CBondSorter.h"

#include <core/strings/string_convert.h>
#include <core/strings/string_util.h>
#include <qbprotocol/include/SSQBAModel.h>
#include <qbprotocol/proto/table/common_util.h>
#include <uam/ServerTimeMgr.h>
#include <uam/UserAccountManager.h>

#include <mutex>

#include "../ABBondPriceInfo.h"
#include "../ABSBondInfo.h"
#include "../BondCDCPriceInfo.h"
#include "../BondCSIPriceInfo.h"
#include "../BondDict.h"
#include "../BondLiquidity.h"
#include "../BondType.h"
#include "../IssuerLiquidity.h"
#include "../MarketMakeTarget.h"
#include "../QBIssuerInfo.h"
#include "../QBProviceInfo.h"
#include "../QBSortVContainer.h"
#include "../QBSwSectorInfo.h"
#include "../SSCompanyReportManager.h"
#include "BrokerKeyInfo.h"
#include "CTakenPriceMap.h"

#define MIN_VAL -1E8
#define MAX_VAL 1E12
#define MIN_UNAUTH_VALUE -1E7  // 用于没有权限的最小双精度数

#define atof qb::proto::MathUtil::atof
#define atoi qb::proto::MathUtil::atoi

#define SASSERT        //
#define STACK_METRICS  //

#ifndef _MSC_VER
#define RTL_FIELD_SIZE(type, field) (sizeof(((type*)0)->field))
#endif

#define StringCopy qb::base::StringUtil::StringCopy
namespace {
inline bool IsEmpty(const char* str) {
  // 旧代码是 strlen(str)<=0;
  return str == NULL || *str == '\0';
}
}  // namespace
double CBondUtil::GetBuyPrice(const BrokerKey& key) {
  double idval = 0;
  REPORT* iRpt = GetCompanyInfoById(key.GetBrokerId(), key);
  if (strcmp(iRpt->m_bidinfo.m_price_status, "0") == 0 ||
      iRpt->m_bidinfo.m_sPrice[0] == '\0')  // 显示“--”
  {
    idval = MIN_VAL;
  } else if (strcmp(iRpt->m_bidinfo.m_sPrice, "Bid") == 0) {
    idval = 0.00001;
  } else {
    idval = atof(iRpt->m_bidinfo.m_sPrice);
  }

  return idval;
}
double CBondUtil::GetBuyNetPrice(const BrokerKey& key) {
  double idval = 0;
  REPORT* iRpt = GetCompanyInfoById(key.GetBrokerId(), key);
  if (strcmp(iRpt->m_bidinfo.m_price_status, "0") == 0 ||
      iRpt->m_bidinfo.m_clean_price[0] == '\0')  // 显示“--”
  {
    idval = MIN_VAL;
  } else {
    idval = atof(iRpt->m_bidinfo.m_clean_price);
  }

  return idval;
}
double CBondUtil::GetSellPrice(const BrokerKey& key) {
  double idval = 0;
  REPORT* iRpt = GetCompanyInfoById(key.GetBrokerId(), key);
  if (strcmp(iRpt->m_askinfo.m_price_status, "0") == 0 ||
      iRpt->m_askinfo.m_sPrice[0] == '\0')  // 显示“--”
  {
    idval = MIN_VAL;
  } else if (strcmp(iRpt->m_askinfo.m_sPrice, "Ofr") == 0) {
    idval = 0.00001;
  } else {
    idval = atof(iRpt->m_askinfo.m_sPrice);
  }

  return idval;
}
double CBondUtil::GetSellNetPrice(const BrokerKey& key) {
  double idval = 0;
  REPORT* iRpt = GetCompanyInfoById(key.GetBrokerId(), key);
  if (strcmp(iRpt->m_askinfo.m_price_status, "0") == 0 ||
      iRpt->m_askinfo.m_clean_price[0] == '\0')  // 显示“--”
  {
    idval = MIN_VAL;
  } else {
    idval = atof(iRpt->m_askinfo.m_clean_price);
  }

  return idval;
}
double CBondUtil::GetModifyTime(const BrokerKey& key) {
  /*
  [内存优化][scofined.qi]

  */
  CReportManagerBase::Scoped l(GetBrokerReportManager()->GetMutex());
  CBondCompanyRep* ptmp =
      CBondContainer::instance().GetCompanyRep(key.m_nIndex);
  return ptmp ? ptmp->GetModifyTime(key.GetBrokerId()) : 0;
  // 原始代码
  // REPORT* r1 = GetCompanyInfoById(key.GetBrokerId(),key);
  // time_t maxr1 = max(r1->m_time,r1->m_create_time);
  // return (double)maxr1;
}

REPORT* CBondUtil::GetCompanyInfoById(const std::string& szKey,
                                      const BrokerKey& szID) {
  static REPORT stRep;
  memset(&stRep, 0, sizeof(stRep));
  bool found = false;

  CReportManagerBase::Scoped l(GetBrokerReportManager()->GetMutex());
  CBondContainer::instance().GetCompanyRepById(szID.m_nIndex, szKey.c_str(),
                                               stRep);
  return &stRep;
}

double CBondUtil::GetCFETSModifyTime(const BrokerKey& key) {
  int type = atoi(key.GetBrokerId().c_str());
  if (type <= CCFETSQuote::QINVALID || type >= CCFETSQuote::QMAX) return 0.0;

  CReportManagerBase::Scoped l(CfetsRepMng->GetMutex());

  CFETSQUOTE quote;
  CCFETSQuoteRep* ptmp = CBondContainer::instance().GetCFETSQuote(key.m_nIndex);
  if (ptmp)
    ptmp->GetQuoteByKey(
        (CCFETSQuote::CFETSQUOTETYPE)atoi(key.GetBrokerId().c_str()), quote);
  return (double)quote.m_time;
}

double CBondUtil::GetCFETSRawDouble(const BrokerKey& key, int kPrcType,
                                    BYTE btSettlement) {
  CFETSQUOTE* pCfetsQuote = GetCFETSQuoteById(key, btSettlement);
  double dValue = MIN_VAL;
  if (pCfetsQuote == nullptr) return dValue;  // 返回出口1
  char* pRaw = nullptr;
  int nBasicComType = 0;  // 0 vol 1 bid 2 ofr
  switch (kPrcType) {
    case kCFETS_BidFull:  // CFETS 全价 bid
      nBasicComType = 1;
      pRaw = pCfetsQuote->m_BidPriceFull;
      break;
    case kCFETS_BidVol:  // CFETS bid 量
      pRaw = pCfetsQuote->m_BidVol;
      break;
    case kCFETS_BidClean:  // CFETS 净价 bid
      nBasicComType = 1;
      pRaw = pCfetsQuote->m_BidPriceClean;
      break;
    case kCFETS_Bid:  // CFETS  bid
      nBasicComType = 1;
      pRaw = pCfetsQuote->m_BidPriceYield;
      break;
    case kCFETS_Ofr:  // CFETS  ofr
      nBasicComType = 2;
      pRaw = pCfetsQuote->m_OfrPriceYield;
      break;
    case kCFETS_OfrClean:  // CFETS 净价ofr
      nBasicComType = 2;
      pRaw = pCfetsQuote->m_OfrPriceClean;
      break;
    case kCFETS_OfrVol:  // CFETS ofr 量
      pRaw = pCfetsQuote->m_OfrVol;
      break;
    case kCFETS_OfrFull:  // CFETS 全价 ofr
      nBasicComType = 2;
      pRaw = pCfetsQuote->m_OfrPriceFull;
      break;
    default:
      break;
  }
  if (pRaw != nullptr) {
    switch (nBasicComType) {
      case 0: {
        if (IsEmpty(pRaw)) break;
        dValue = atof(pRaw);
        break;
      }
      case 1: {
        if (IsEmpty(pRaw) || strcmp(pRaw, "0") == 0 ||
            strcmp(pRaw, "bid") == 0 || strcmp(pRaw, "Bid") == 0)
          break;
        dValue = atof(pRaw);
        break;
      }
      case 2: {
        if (IsEmpty(pRaw) || strcmp(pRaw, "0") == 0 ||
            strcmp(pRaw, "ofr") == 0 || strcmp(pRaw, "Ofr") == 0)
          break;
        dValue = atof(pRaw);
        break;
      }
      default:
        break;
    }
  }
  return dValue;
}

CFETSQUOTE* CBondUtil::GetCFETSQuoteById(const BrokerKey& key,
                                         BYTE btSettlement) {
  // 有性能问题，每次需要拷贝数据
  static CFETSQUOTE stRep;
  stRep.Clear();  // 内含string
  int type = atoi(key.GetBrokerId().c_str());
  if (type > CCFETSQuote::QINVALID && type < CCFETSQuote::QMAX) {
    CReportManagerBase::Scoped l(CfetsRepMng->GetMutex());
    CCFETSQuoteRep* ptmp =
        CBondContainer::instance().GetCFETSQuote(key.m_nIndex);
    if (ptmp) {
      ptmp->GetQuoteByKey(
          (CCFETSQuote::CFETSQUOTETYPE)atoi(key.GetBrokerId().c_str()), stRep);
      if (btSettlement != 0) {
        CBondContainer::instance().FilterQuoteByClearSpeed(stRep, btSettlement);
      }
    }
  }
  return &stRep;
}

xQBCFETSDealAllUnit* CBondUtil::GetCFETSDealById(const BrokerKey& key) {
  // 有性能问题，每次需要拷贝数据
  static xQBCFETSDealAllUnit unit;
  memset(&unit, 0, sizeof(xQBCFETSDealAllUnit));

  CReportManagerBase::Scoped l(CfetsDealRepMng->GetMutex());
  CCFETSDealQuoteRep* ptmp =
      CBondContainer::instance().GetCFETSDealQuote(key.m_nIndex);
  if (ptmp) ptmp->GetDealQuote(unit);

  return &unit;
}

// 清算速度相关
double CBondUtil::GetBuyPriceBySettlement(const BrokerKey& key,
                                          BYTE btPriceFilter, bool bAscend) {
  double idval = MIN_VAL;
  REPORT* iRpt =
      GetCompanyInfoByIdAndSettlement(key.GetBrokerId(), key, btPriceFilter);

  if (strcmp(iRpt->m_bidinfo.m_price_status, "0") == 0 ||
      iRpt->m_bidinfo.m_sPrice[0] == '\0')  // 显示“--”
  {
    if (!bAscend)
      idval = MIN_VAL;
    else
      idval = MAX_VAL;
  } else if (strcmp(iRpt->m_bidinfo.m_sPrice, "Bid") == 0) {
    idval = 0.00001;
  } else {
    idval = atof(iRpt->m_bidinfo.m_sPrice);
  }

  return idval;
}
double CBondUtil::GetBuyNetPriceBySettlement(const BrokerKey& key,
                                             BYTE btPriceFilter, bool bAscend) {
  double idval = MIN_VAL;
  REPORT* iRpt =
      GetCompanyInfoByIdAndSettlement(key.GetBrokerId(), key, btPriceFilter);

  if (strcmp(iRpt->m_bidinfo.m_price_status, "0") == 0 ||
      iRpt->m_bidinfo.m_clean_price[0] == '\0')  // 显示“--”
  {
    if (!bAscend)
      idval = MIN_VAL;
    else
      idval = MAX_VAL;
  } else {
    idval = atof(iRpt->m_bidinfo.m_clean_price);
  }

  return idval;
}

double CBondUtil::GetBuyFullPriceBySettlement(const BrokerKey& key,
                                              BYTE btPriceFilter,
                                              bool bAscend) {
  double idval = MIN_VAL;
  REPORT* iRpt =
      GetCompanyInfoByIdAndSettlement(key.GetBrokerId(), key, btPriceFilter);

  if (strcmp(iRpt->m_bidinfo.m_price_status, "0") == 0 ||
      iRpt->m_bidinfo.m_full_price[0] == '\0')  // 显示“--”
  {
    if (!bAscend)
      idval = MIN_VAL;
    else
      idval = MAX_VAL;
  } else {
    idval = atof(iRpt->m_bidinfo.m_full_price);
  }

  return idval;
}

double CBondUtil::GetSellPriceBySettlement(const BrokerKey& key,
                                           BYTE btPriceFilter, bool bAscend) {
  double idval = MIN_VAL;
  REPORT* iRpt =
      GetCompanyInfoByIdAndSettlement(key.GetBrokerId(), key, btPriceFilter);

  if (strcmp(iRpt->m_askinfo.m_price_status, "0") == 0 ||
      iRpt->m_askinfo.m_sPrice[0] == '\0')  // 显示“--”
  {
    if (!bAscend)
      idval = MIN_VAL;
    else
      idval = MAX_VAL;
  } else if (strcmp(iRpt->m_askinfo.m_sPrice, "Ofr") == 0) {
    idval = 0.00001;
  } else {
    idval = atof(iRpt->m_askinfo.m_sPrice);
  }

  return idval;
}
double CBondUtil::GetSellNetPriceBySettlement(const BrokerKey& key,
                                              BYTE btPriceFilter,
                                              bool bAscend) {
  double idval = MIN_VAL;
  REPORT* iRpt =
      GetCompanyInfoByIdAndSettlement(key.GetBrokerId(), key, btPriceFilter);

  if (strcmp(iRpt->m_askinfo.m_price_status, "0") == 0 ||
      iRpt->m_askinfo.m_clean_price[0] == '\0')  // 显示“--”
  {
    if (!bAscend)
      idval = MIN_VAL;
    else
      idval = MAX_VAL;
  } else {
    idval = atof(iRpt->m_askinfo.m_clean_price);
  }
  return idval;
}

double CBondUtil::GetSellFullPriceBySettlement(const BrokerKey& key,
                                               BYTE btPriceFilter,
                                               bool bAscend) {
  double idval = MIN_VAL;
  REPORT* iRpt =
      GetCompanyInfoByIdAndSettlement(key.GetBrokerId(), key, btPriceFilter);

  if (strcmp(iRpt->m_askinfo.m_price_status, "0") == 0 ||
      iRpt->m_askinfo.m_full_price[0] == '\0')  // 显示“--”
  {
    if (!bAscend)
      idval = MIN_VAL;
    else
      idval = MAX_VAL;
  } else {
    idval = atof(iRpt->m_askinfo.m_full_price);
  }
  return idval;
}

double CBondUtil::GetModifyTimeBySettlement(const BrokerKey& key,
                                            BYTE btSettlement) {
  REPORT* iRpt =
      GetCompanyInfoByIdAndSettlement(key.GetBrokerId(), key, btSettlement);

  time_t t = max(iRpt->m_create_time, iRpt->m_time);
  return (double)t;
}

REPORT* CBondUtil::GetCompanyInfoByIdAndSettlement(const std::string& szKey,
                                                   const BrokerKey& szID,
                                                   BYTE btPriceFilter) {
  static REPORT stRep;
  memset(&stRep, 0, sizeof(REPORT));

  CReportManagerBase::Scoped l(GetBrokerReportManager()->GetMutex());
  CBondContainer::instance().GetCompanyRepByIdAndSettlement(
      szID.m_nIndex, szKey.c_str(), btPriceFilter, stRep);
  return &stRep;
}

REPORT* CBondUtil::GetMixedBestPrice(const BrokerKey& key, BYTE btPriceFilter) {
  static REPORT stRep;
  memset(&stRep, 0, sizeof(REPORT));

  CReportManagerBase::Scoped l(BrokerBPRepMng->GetMutex());
  CBondContainer::instance().GetBrokerMixedBPRepByIdAndPriceFilter(
      key.m_nIndex, key.GetBrokerId().c_str(), btPriceFilter, stRep);
  return &stRep;
}

double CBondUtil::GetMixedBPBuyPrice(const BrokerKey& key, BYTE btPriceFilter,
                                     bool bAscend) {
  double idval = 0;
  REPORT* rpt = GetMixedBestPrice(key, btPriceFilter);
  if (strcmp(rpt->m_bidinfo.m_price_status, "0") == 0)  // 无效报价，显示“--”
  {
    if (!bAscend)
      idval = MIN_VAL;
    else
      idval = MAX_VAL;
  } else if (strcmp(rpt->m_bidinfo.m_quotetype, "0") == 0 ||
             strcmp(rpt->m_bidinfo.m_sPrice, "Bid") == 0 ||
             (rpt->m_bidinfo.m_sPrice[0] == '\0' &&
              rpt->m_bidinfo.m_sVolume[0] != '\0'))  // 意向价
    idval = 0.00001;
  else if (rpt->m_bidinfo.m_sPrice[0] != '\0')  // 有效报价
    idval = atof(rpt->m_bidinfo.m_sPrice);
  else  // 不符合规则，无效报价
  {
    if (!bAscend)
      idval = MIN_VAL;
    else
      idval = MAX_VAL;
  }
  return idval;
}

double CBondUtil::GetMixedBPBuyNetPrice(const BrokerKey& key,
                                        BYTE btPriceFilter, bool bAscend) {
  double idval = 0;
  REPORT* rpt = GetMixedBestPrice(key, btPriceFilter);

  if (strcmp(rpt->m_bidinfo.m_price_status, "0") == 0 ||
      rpt->m_bidinfo.m_clean_price[0] == '\0')  // 显示“--”
  {
    if (!bAscend)
      idval = MIN_VAL;
    else
      idval = MAX_VAL;
  } else
    idval = atof(rpt->m_bidinfo.m_clean_price);
  return idval;
}

double CBondUtil::GetMixedBPBuyFullPrice(const BrokerKey& key,
                                         BYTE btPriceFilter, bool bAscend) {
  double idval = 0;
  REPORT* rpt = GetMixedBestPrice(key, btPriceFilter);

  if (strcmp(rpt->m_bidinfo.m_price_status, "0") == 0 ||
      rpt->m_bidinfo.m_full_price[0] == '\0')  // 显示“--”
  {
    if (!bAscend)
      idval = MIN_VAL;
    else
      idval = MAX_VAL;
  } else
    idval = atof(rpt->m_bidinfo.m_full_price);
  return idval;
}

double CBondUtil::GetMixedBPSellPrice(const BrokerKey& key, BYTE btPriceFilter,
                                      bool bAscend) {
  double idval = 0;
  REPORT* rpt = GetMixedBestPrice(key, btPriceFilter);
  if (strcmp(rpt->m_askinfo.m_price_status, "0") == 0)  // 无效报价，显示“--”
  {
    if (!bAscend)
      idval = MIN_VAL;
    else
      idval = MAX_VAL;
  } else if (strcmp(rpt->m_askinfo.m_quotetype, "0") == 0 ||
             strcmp(rpt->m_askinfo.m_sPrice, "Bid") == 0 ||
             (rpt->m_askinfo.m_sPrice[0] == '\0' &&
              rpt->m_askinfo.m_sVolume[0] != '\0'))  // 意向价
    idval = 0.00001;
  else if (rpt->m_askinfo.m_sPrice[0] != '\0')  // 有效报价
    idval = atof(rpt->m_askinfo.m_sPrice);
  else  // 不符合规则，无效报价
  {
    if (!bAscend)
      idval = MIN_VAL;
    else
      idval = MAX_VAL;
  }
  return idval;
}

double CBondUtil::GetMixedBPSellNetPrice(const BrokerKey& key,
                                         BYTE btPriceFilter, bool bAscend) {
  double idval = 0;
  REPORT* rpt = GetMixedBestPrice(key, btPriceFilter);

  if (strcmp(rpt->m_askinfo.m_price_status, "0") == 0 ||
      rpt->m_askinfo.m_clean_price[0] == '\0')  // 显示“--”
  {
    if (!bAscend)
      idval = MIN_VAL;
    else
      idval = MAX_VAL;
  } else
    idval = atof(rpt->m_askinfo.m_clean_price);
  return idval;
}

double CBondUtil::GetMixedBPSellFullPrice(const BrokerKey& key,
                                          BYTE btPriceFilter, bool bAscend) {
  double idval = 0;
  REPORT* rpt = GetMixedBestPrice(key, btPriceFilter);

  if (strcmp(rpt->m_askinfo.m_price_status, "0") == 0 ||
      rpt->m_askinfo.m_full_price[0] == '\0')  // 显示“--”
  {
    if (!bAscend)
      idval = MIN_VAL;
    else
      idval = MAX_VAL;
  } else
    idval = atof(rpt->m_askinfo.m_full_price);
  return idval;
}

double CBondUtil::GetMixedBPModifyTime(const BrokerKey& key,
                                       BYTE btPriceFilter) {
  REPORT* rpt = GetMixedBestPrice(key, btPriceFilter);
  return (double)(rpt->m_time);
}

typedef CBondSorter::SortInfo SortInfo;
namespace {
inline double ToDashFloat(const char* str) {
  // 同CSSImpSortBondAllBroker中的MIN_VAL
  if (str && *str != 0) {
    if (str[0] == '-' && str[1] == '-') return MIN_VAL;
    return atof(str);
  }
  return MIN_VAL;
}
inline double ToSpecialFloat(const char* str, bool bAscend) {
  if (str && *str != 0) {
    if (str[0] == '-' && str[1] == '-') {
      if (!bAscend)
        return MIN_VAL;
      else
        return MAX_VAL;
    }
    return atof(str);
  }
  return bAscend ? MAX_VAL : MIN_VAL;
}

#ifndef WIN32
#include <sys/stat.h>

#include <ctime>
#endif

bool IsFileChanged(const char* fname, void* lastWriteTime) {
  bool changed = false;
  if (!IsEmpty(fname)) {
#ifdef WIN32
    DWORD share = FILE_SHARE_WRITE | FILE_SHARE_READ;
    HANDLE hfile = CreateFileA(fname, GENERIC_READ, share, 0, OPEN_EXISTING,
                               FILE_ATTRIBUTE_NORMAL, 0);
    FILETIME last_write = {0};
    if (hfile != INVALID_HANDLE_VALUE && hfile != 0) {
      FILETIME* cur = (FILETIME*)lastWriteTime;
      if (GetFileTime(hfile, 0, 0, &last_write) &&
          CompareFileTime(&last_write, cur) > 0) {
        *cur = last_write;
        changed = true;
      }
    }
    if (hfile) CloseHandle(hfile);
#else
    struct stat fileStat;
    // TODO: 这里暂时注释掉了
    //  if (stat(fname, &fileStat) == 0) {
    //    if (lastWriteTime->tv_sec < fileStat.st_mtim.tv_sec ||
    //        (lastWriteTime->tv_sec == fileStat.st_mtim.tv_sec &&
    //         lastWriteTime->tv_nsec < fileStat.st_mtim.tv_nsec)) {
    //      *lastWriteTime = fileStat.st_mtim;
    //      changed = true;
    //    }
    //  }
#endif
  }

  return changed;
  return false;
}

class CBoolChecker {
  std::string m_filename;
  std::set<std::string> m_checkers;
  bool m_initialized;
#ifdef WIN32
  FILETIME m_lastwrite;
#else
  struct stat m_lastwrite;
#endif

 public:
  static CBoolChecker& Get() {
    static CBoolChecker cbc;
    return cbc;
  }
  CBoolChecker() : m_initialized(false), m_filename("./config/checkers.ini") {
    memset(&m_lastwrite, 0, sizeof(m_lastwrite));
  }
  ~CBoolChecker() {}
  bool GetCheckBool(const char* name) {
    if (!m_initialized || IsFileChanged(m_filename.c_str(), &m_lastwrite)) {
      m_checkers.clear();
      m_initialized = true;
      std::vector<qb::base::BaseString> lines;
      qb::base::StringUtil::LoadLinesFromFile(qb::base::G2W(m_filename.c_str()),
                                              lines);
      for (int i = 0; i < (int)lines.size() && i < 10; i++) {
        qb::base::BaseString& line = lines.at(i);
        qb::base::strinfo tokens[2];
        int num = qb::base::StringUtil::SplitStringInfo(
            line.c_str(), line.size(), " =\t", tokens, 2);
        if (num >= 2) {
          qb::base::BaseString value =
              qb::base::BaseString(line.c_str() + tokens[1].pos, tokens[1].len);
          if (qstricmp(value.c_str(), "true") == 0)
            m_checkers.insert(qb::base::BaseString(line.c_str() + tokens[0].pos,
                                                   tokens[0].len)
                                  .c_str());
        }
      }
    }
    if (m_checkers.empty()) return false;
    std::set<std::string>::iterator it = m_checkers.find(name);
    return it != m_checkers.end();
  };
};

class RatingRankManager {
  typedef std::map<string, int> RankMap;
  bool m_initialized;
  std::mutex m_init_lock;
  RankMap m_rankmap;

 public:
  static RatingRankManager& Get() {
    static RatingRankManager rrm;
    return rrm;
  }
  RatingRankManager() : m_initialized(false) {}
  int GetRatingRank(const std::string& sRating) {
    if (!m_initialized) {
      std::lock_guard<std::mutex> scoped(m_init_lock);
      if (!m_initialized) {
        Init();
        m_initialized = true;
      }
    }
    RankMap::const_iterator pos = m_rankmap.find(sRating);
    if (pos != m_rankmap.end()) {
      return pos->second;
    }
    return -1;
  }

 protected:
  void Init() {
    int nIndex = 0;
    m_rankmap[""] = nIndex;
    m_rankmap["--"] = nIndex;
    m_rankmap["CCL"] = nIndex++;
    m_rankmap["D"] = nIndex++;
    m_rankmap["C-3"] = nIndex++;
    m_rankmap["C-2"] = nIndex++;
    m_rankmap["C-"] = nIndex++;
    m_rankmap["C-"] = nIndex++;
    m_rankmap["C"] = nIndex++;
    m_rankmap["C+"] = nIndex++;
    m_rankmap["CC-"] = nIndex++;
    m_rankmap["CC"] = nIndex++;
    m_rankmap["CC+"] = nIndex++;
    m_rankmap["CCC-"] = nIndex++;
    m_rankmap["C-1"] = nIndex++;
    m_rankmap["CCC"] = nIndex++;
    m_rankmap["CCC+"] = nIndex++;
    m_rankmap["B-3"] = nIndex++;
    m_rankmap["B-2"] = nIndex++;
    m_rankmap["B-"] = nIndex++;
    m_rankmap["B"] = nIndex++;
    m_rankmap["B+"] = nIndex++;
    m_rankmap["BB-"] = nIndex++;
    m_rankmap["BB"] = nIndex++;
    m_rankmap["BB+"] = nIndex++;
    m_rankmap["BBB-"] = nIndex++;
    m_rankmap["B-1"] = nIndex++;
    m_rankmap["BBB"] = nIndex++;
    m_rankmap["BBB+"] = nIndex++;
    m_rankmap["A-3"] = nIndex++;
    m_rankmap["A-2"] = nIndex++;
    m_rankmap["A-"] = nIndex++;
    m_rankmap["A"] = nIndex++;
    m_rankmap["A+"] = nIndex++;
    m_rankmap["AA-"] = nIndex++;
    m_rankmap["AA2"] = nIndex++;
    m_rankmap["AA(2)"] = nIndex++;
    m_rankmap["AA"] = nIndex++;
    m_rankmap["AA+"] = nIndex++;
    m_rankmap["AAA-"] = nIndex++;
    m_rankmap["A-1"] = nIndex++;
    m_rankmap["AAA"] = nIndex++;
    m_rankmap["AAA+"] = nIndex++;  // AAA+ > AAA > A-1 > AAA- > AA+ > AA > AA- >
                                   // A+ > A > A- > A-2 > A-3 > BBB+ > BBB
  }
};

enum kSortType {
  kSortTypeString,
  kSortTypeDouble,
  kSortTypeInt,
  kSortTypeChar,
  kSortTypeBidLimit,         // double	bottom,top
  kSortTypeMaturityTermEnd,  //
  kSortTypeTermToMaturity,
  kSortTypeIssuePeriod  //
};

#define GetBond(i) CBondContainer::instance().ElementAtR(i)

struct IssuePeriod {
  int nBondIndex;
  int nAscend;
  int nDate;
};
class BondReader {
  CTakenPriceMap m_taken_price_map;  // 在比较VTKNPRICE的时候需要
  SSUserAccountManager::CDCAuthKey
      m_cdcauthKey;  // 一旦设定,需要下次点击重排才更新
  bool m_hascdcrights;
  bool m_csiauth;

 public:
  static bool IsRequireCDCAuthority(VSortKey key) {
    // 哪些字段需要CDC权限
    switch (key) {
      case VESTBPRICEPRE:    // 昨日中债估值,double
      case VESTBPRICETODAY:  // 今日中债估值,double
      case kDuration:        // 久期,double
      case kCdcCleanPrice:   // 中债净价,double
      case kBid_EstPrice:    // bid-中债,double
      case kEstPrice_Ofr:    // 中债-ofr,double
      case kCsi_Cdc:         // 中证一中债,double
      case kDeal_Cdc:        // 成交-中债,double
      case kCFETS_Bid_CdcVal:
      case kCFETS_CdcVal_Ofr:
        return true;
    }
    return false;
  }
  virtual ~BondReader() {}
  int GetInstitutionSortId(const char* institutionType) {
    static std::map<string, int> mapInstType;
    if (mapInstType.size() <= 0) {
      mapInstType["CGE"] = CBondContainer::InstCentr;
      mapInstType["LGE"] = CBondContainer::InstConty;
      mapInstType["PVE"] = CBondContainer::InstPrvat;
      mapInstType["OTE"] = CBondContainer::InstOther;
    }

    BondDict dict_item_i;
    CBondDict::instance().GetBondDict("institution_subtype", institutionType,
                                      dict_item_i);
    int nSort1;
    std::map<string, int>::iterator itr1 =
        mapInstType.find(dict_item_i.selective_code);
    if (itr1 == mapInstType.end())
      nSort1 = CBondContainer::InstOther + 1;
    else
      nSort1 = itr1->second;
    return nSort1;
  }
  static int CalMaturityTerm(const std::string& sPrePeriod) {  // 用于期限排序
    string sPeriod = sPrePeriod;
    if (sPeriod.empty()) return -1;

    size_t pos = sPeriod.find("+");
    if (pos >= 2) sPeriod = sPeriod.substr(0, pos - 1);
    if (sPeriod[sPeriod.length() - 1] == 'Y' ||
        sPeriod[sPeriod.length() - 1] == 'y') {
      return atof(sPeriod.substr(0, sPeriod.length() - 1).c_str()) * 365;
    } else if (sPeriod[sPeriod.length() - 1] == 'M' ||
               sPeriod[sPeriod.length() - 1] == 'm') {
      return atof(sPeriod.substr(0, sPeriod.length() - 1).c_str()) * 30;
    } else if (sPeriod[sPeriod.length() - 1] == 'W' ||
               sPeriod[sPeriod.length() - 1] == 'w') {
      return atof(sPeriod.substr(0, sPeriod.length() - 1).c_str()) * 7;
    } else if (sPeriod[sPeriod.length() - 1] == 'D' ||
               sPeriod[sPeriod.length() - 1] == 'd') {
      return atof(sPeriod.substr(0, sPeriod.length() - 1).c_str());
    } else
      return -999;
  }
  static IssuePeriod GetIssuePeriodSortId(int bid) {
    const char* strDate_1 = GetBond(bid).GetIssueStartDate();
    int iDate_1 = strDate_1 == NULL ? 0 : atoi(strDate_1);
    // 2016/07/27,bushion.xin:发行时间列排序为今日>非今日（今日之前）>非今日（今日之后）>issue_period有值>--
    int nAscend_1 =
        0;  // 今日:8;非今日（今日之前）:6;非今日（今日之后）:4;issue_period有值:2;--:0
    bool bIssuePeriod1 = false;

    // 判断今日及今日之后，之前
    time_t tTime = ServerTimeMgr::instance().serverTime();
    tm stTm = qb::base::time2tm(tTime);

    char strTm[12] = {0};
    strftime(strTm, 12, "%Y%m%d", &stTm);
    int nToday = atoi(strTm);

    if (iDate_1 == nToday) {
      nAscend_1 = 8;
    } else if (iDate_1 > nToday) {
      nAscend_1 = 4;
    } else if (iDate_1 > 0 && iDate_1 < nToday) {
      nAscend_1 = 6;
    }

    if (!IsEmpty(GetBond(bid).GetIssuePeriod())) {
      bIssuePeriod1 = true;
      nAscend_1 = 2;
    }
    if (bIssuePeriod1) {
      iDate_1 = 0;
    }
    IssuePeriod ip;
    ip.nAscend = nAscend_1;
    ip.nDate = iDate_1;
    ip.nBondIndex = bid;
    return ip;
  }
  double GetTakenCdc(const BrokerKey& key, const int i, bool bIsCDCAuthValid,
                     bool bAscend) {  // 成交-中债,此处值作为比较
    const char* takenstr = m_taken_price_map.GetYeildStr(key);
    int exec = m_taken_price_map.GetExec(key);
    if (takenstr == nullptr || takenstr[0] == '\0' ||
        strcmp(takenstr, "--") == 0)
      return (bAscend ? MAX_VAL : _INVALID_CSI_VALUE);
    double taken = CBondCDCPriceInfo::instance().GetYesterdayCDCPriceGap(
        bIsCDCAuthValid, i, CBondCDCPriceInfo::price_type_yield, true, takenstr,
        INVALID_CDC_VALUE, exec);
    if (taken <= INVALID_CDC_VALUE)
      return (bAscend ? MAX_VAL : _INVALID_CSI_VALUE);
    return taken;
  }
  double GetTakenCsi(const BrokerKey& key, const CBondInfo& bi,
                     bool bAscend) {  // 成交-中证,此处值作为比较
    /*const char* takenstr = m_taken_price_map.GetClearPriceStr(key);
    double taken = (takenstr && strlen(takenstr) > 0) ? atof(takenstr) : 0.0;*/
    double taken = m_taken_price_map.GetYieldCalc(key);
    // const char*csistr = bi.GetCSYield();
    // if (taken >= 30.0 || taken == 0.0 || IsEmpty(csistr))
    //	return -100.0;
    // return taken - atof(csistr);

    // double taken = atof(sDeal.c_str());

    if (taken >= 30.0 || taken == 0.0)
      return (bAscend ? MAX_VAL : _INVALID_CSI_VALUE);

    double dRet = _INVALID_CSI_VALUE;

    xCSIUint_c xUnit;
    if (CBondCSInfo::instance().GetCsiUnit(bi.GetCombBondKey(), xUnit)) {
      double dExercise = xUnit.IsHaveExercise() ? xUnit.m_dYieldToExercise
                                                : _INVALID_CSI_VALUE;
      double dMaturity = xUnit.IsHaveMarturity() ? xUnit.m_dYieldToMaturity
                                                 : _INVALID_CSI_VALUE;

      if (dExercise > _INVALID_CSI_VALUE && dMaturity > _INVALID_CSI_VALUE) {
        dExercise = taken - dExercise;
        dMaturity = taken - dMaturity;
        dRet = abs(dExercise) < abs(dMaturity) ? dExercise : dMaturity;
      } else if (dExercise > _INVALID_CSI_VALUE) {
        dRet = taken - dExercise;
      } else if (dMaturity > _INVALID_CSI_VALUE) {
        dRet = taken - dMaturity;
      }
    }
    if (dRet == _INVALID_CSI_VALUE) return (bAscend ? MAX_VAL : dRet);
    return dRet;
  }

 public:
  virtual void PreGetRecordField(const std::vector<SortInfo>& orders,
                                 int corpid) {
    // see CSSVContainer::SortBrokerKey  7490
    // see m_pSortBondMng->UpdateSortData(this);
    m_taken_price_map.Clear();
    for (int i = 0; i < (int)orders.size(); i++) {
      const SortInfo& co = orders[i];
      if (IsRequireCDCAuthority((VSortKey)co.column_id)) {
        m_cdcauthKey = SSUserAccountManager::instance().GetCDCAutorityKey();
        m_hascdcrights = SSUserAccountManager::instance().HasAnyCDCAuthority();
        break;
      }
    }
    m_taken_price_map.SetWithYieldStr(false);
    m_csiauth = SSUserAccountManager::instance().GetCSIAuthorityFlag();
    for (int i = 0; i < (int)orders.size(); i++) {
      const SortInfo& co = orders[i];
      if (co.column_id == kTknPrice || co.column_id == kTknYield ||
          co.column_id == kCleanPriceDiv || co.column_id == kYieldDiv ||
          co.column_id == VTKNPRICE || co.column_id == kDeal_Cdc ||
          co.column_id == kDeal_Csi || co.column_id == kCFETS_Deal_CDC ||
          co.column_id == kCFETS_Deal_CSI) {
        m_taken_price_map.SetWithYieldStr(true);
        m_taken_price_map.SetMap(corpid);
        break;
      }
    }
  }
  double GetTknPrice(const BrokerKey& key, const CBondInfo& bi, bool batchMode,
                     bool bBestQuotePage = false, bool bAscend = true) {
    // batchMode 为true，表明当前界面触发手动全部排序
    // batchMode 为false，表明当前界面正在更新最新记录，自动维持有序
    // 一下几个函数的batchMode类似
    // 之前，维持有序阶段，没有做PreGetRecordField，也无法做（代价太高），可能导致
    // 界面中的成交列排序错误，手动点击排序后会进入batchMode=true阶段，会修正
    // case kTknCleanPrice://compare_clean_price,成交净价
    //	*((double*)field) = m_taken_price_map.GetCleanPrice(key);
    // MarketStreamType2Body.m_price
    if (batchMode)
      return m_taken_price_map.GetCleanPrice(key, bBestQuotePage, bAscend);

    if (atoi(key.GetBrokerId().c_str()) == 0) {
      static std::vector<std::string> _mapBroker;
      static bool _brokerInited = false;
      if (!_brokerInited) {
        const CBrokerList::BrokerMap& constMap =
            SSUserAccountManager::instance().GetReadonlyBroker().GetBrokerMap();
        for (CBrokerList::BrokerMap::const_iterator it = constMap.begin();
             it != constMap.end(); ++it) {
          char sBrokerID[33] = {0};
          FMTBUF(sBrokerID, "%d", it->first);
          _mapBroker.push_back(sBrokerID);
        }
        _brokerInited = true;
      }
      time_t lastUpdate = 0;
      MarketStreamInfo lastInfo;
      bool bValid = false;
      for (std::vector<std::string>::const_iterator it = _mapBroker.begin();
           it != _mapBroker.end(); it++) {
        MarketStreamInfo info;
        if (CMarketStream::bondStream().GetMarketStreamByKey(
                bi.GetCombBondKey(), it->c_str(), info)) {
          if (info.m_modify_time > lastUpdate) {
            lastInfo = info;
            lastUpdate = info.m_modify_time;
            bValid = true;
          }
        }
      }
      return bValid ? atof(lastInfo.m_body.m_price)
                    : (bBestQuotePage ? (bAscend ? MAX_VAL : 0.0) : 0.0);
    } else {
      MarketStreamInfo info;
      if (CMarketStream::bondStream().GetMarketStreamByKey(
              bi.GetCombBondKey(), key.GetBrokerId().c_str(), info))
        return atof(info.m_body.m_price);
      return bBestQuotePage ? (bAscend ? MAX_VAL : 0.0) : 0.0;
    }
  }
  double GetCleanPriceDiv(const BrokerKey& key, const int nBondIndex,
                          const CBondInfo& bi, bool batchMode) {
    // case kCleanPriceDiv://compare_clean_price_div,净价偏离度
    //	*((double*)field) = m_taken_price_map.GetCleanPriceDiv(key);
    //  需要计算出来，参见QBSortVContainer.cpp的::GetCleanPriceDiv
    if (batchMode) return m_taken_price_map.GetCleanPriceDiv(key);
    const double min_value = -1E5;
    MarketStreamInfo info;
    CMarketStream::bondStream().GetMarketStreamByKey(
        bi.GetCombBondKey(), key.GetBrokerId().c_str(), info);
    const char* pszPriceDiv = ::GetCleanPriceDiv(
        info.m_body.m_cleanPrice,
        CBondCDCPriceInfo::instance()
            .GetRelaEstimatePrice(bi.IsCDCAuthValid(), nBondIndex,
                                  CBondCDCPriceInfo::price_type_clean,
                                  info.m_body.m_cleanPrice)
            .c_str());
    if (pszPriceDiv != NULL && strcmp(pszPriceDiv, "--") == 0) {
      return min_value;
    } else {
      return atof(pszPriceDiv);
    }
  }
  double GetYield(const BrokerKey& key, const CBondInfo& bi, bool batchMode) {
    // case kTknYield://compare_tkn_yield,成交收益率
    //	*((double*)field) = m_taken_price_map.GetYield(key);
    //  MarketStreamType2Body.m_yield
    if (batchMode) return m_taken_price_map.GetYield(key);
    MarketStreamInfo info;
    CMarketStream::bondStream().GetMarketStreamByKey(
        bi.GetCombBondKey(), key.GetBrokerId().c_str(), info);
    return atof(info.m_body.m_yield);
  }
  double GetYieldDiv(const BrokerKey& key, const int nBondIndex,
                     const CBondInfo& bi, bool batchMode) {
    // case kYieldDiv://compare_yield_div,收益率偏离度
    //	*((double*)field) = m_taken_price_map.GetYieldDiv(key);
    //  需要计算出来，参见QBSortVContainer.cpp的::GetYieldDiv
    const double min_value = -1E5;
    if (batchMode) return m_taken_price_map.GetYieldDiv(key);
    MarketStreamInfo info;
    CMarketStream::bondStream().GetMarketStreamByKey(
        bi.GetCombBondKey(), key.GetBrokerId().c_str(), info);
    const char* pszYieldDiv = ::GetYieldDiv(
        CBondCDCPriceInfo::instance()
            .GetRelaEstimatePrice(bi.IsCDCAuthValid(), nBondIndex,
                                  CBondCDCPriceInfo::price_type_yield,
                                  info.m_body.m_yield)
            .c_str(),
        info.m_body.m_yield);
    if (pszYieldDiv != NULL && strcmp(pszYieldDiv, "--") == 0) {
      return min_value;
    } else {
      return atof(pszYieldDiv);
    }
  }

  std::string FmtDealMinusCSI(const char* sCombondkey, std::string sDeal,
                              int type, int exec) {
    if (sDeal.size() <= 0) return "--";

    if (sDeal.compare("--") == 0) return "--";

    double taken = atof(sDeal.c_str());
    // 			if (taken >= 30.0 || taken == 0.0)
    // 				return "--";

    xCSIUint_c xUnit;
    if (!CBondCSInfo::instance().GetCsiUnit(sCombondkey, xUnit)) return "--";

    double dRet = _INVALID_CSI_VALUE;
    double dExercise = _INVALID_CSI_VALUE;
    double dMaturity = _INVALID_CSI_VALUE;
    switch (type) {
      case CBondCSInfo::price_type_yield:
        dExercise = xUnit.IsHaveYieldToExercise() ? xUnit.m_dYieldToExercise
                                                  : _INVALID_CSI_VALUE;
        dMaturity = xUnit.IsHaveYieldToMarturity() ? xUnit.m_dYieldToMaturity
                                                   : _INVALID_CSI_VALUE;
        break;
      case CBondCSInfo::price_type_clean:
        dExercise = xUnit.IsHaveCleanPriceExercise()
                        ? xUnit.m_dCleanPriceExercise
                        : _INVALID_CSI_VALUE;
        dMaturity = xUnit.IsHaveCleanPriceMarturity()
                        ? xUnit.m_dCleanPriceMaturity
                        : _INVALID_CSI_VALUE;
        break;
      case CBondCSInfo::price_type_full:
        dExercise = xUnit.IsHaveFullPriceExercise() ? xUnit.m_dFullPriceExercise
                                                    : _INVALID_CSI_VALUE;
        dMaturity = xUnit.IsHaveFullPriceMarturity()
                        ? xUnit.m_dFullPriceMaturity
                        : _INVALID_CSI_VALUE;
        break;
      default:
        break;
    }

    switch (exec) {
      case 0:
        if (dExercise > _INVALID_CSI_VALUE) {
          dRet = taken - dExercise;
        } else if (dMaturity > _INVALID_CSI_VALUE) {
          dRet = taken - dMaturity;
        }
        break;
      case 1:
        if (dMaturity > _INVALID_CSI_VALUE) {
          dRet = taken - dMaturity;
        } else if (dExercise > _INVALID_CSI_VALUE) {
          dRet = taken - dExercise;
        }
        break;
      case -1:
      default:  // 不限，取偏离最小值
        if (dExercise > _INVALID_CSI_VALUE) {
          if (dMaturity > _INVALID_CSI_VALUE) {
            dExercise = taken - dExercise;
            dMaturity = taken - dMaturity;
            dRet = abs(dExercise) < abs(dMaturity) ? dExercise : dMaturity;
          } else {
            dRet = taken - dExercise;
          }
        } else if (dMaturity > _INVALID_CSI_VALUE) {
          dRet = taken - dMaturity;
        }
        break;
    }

    char buf[128] = "--";
    if (dRet > _INVALID_CSI_VALUE) {
      if (CBondCSInfo::price_type_yield == type)
        FMTBUF(buf, "%.2f", dRet * 100);
      else
        FMTBUF(buf, "%.2f", dRet);
    }
    return buf;
  }

  bool GetRecordField(const BrokerKey& key, int col, char* field, int capcity,
                      BYTE btPriceFilter /*清算速度+报价类型*/,
                      bool batchMode = true, bool bAscend = true) {
    int i = key.m_nIndex;
    const std::string& brokerid = key.GetBrokerId();
    const CBondInfo& bi = GetBond(i);
    switch (col) {
      case VBOND_CODE:
        if (IsEmpty(bi.GetBondCode())) {
          if (!bAscend)
            *field = 0;
          else
            *field = (char)0xFF;
          break;
        }
        StringCopy(field, capcity, bi.GetBondCode());
        break;
      case VSHORT_NAME:
        if (IsEmpty(bi.GetBondShortName())) {
          if (!bAscend)
            *field = 0;
          else
            *field = (char)0xFF;
          break;
        }
        StringCopy(field, capcity, bi.GetBondShortName());
        break;
      case VSHORT_NAME_EN:
        if (IsEmpty(bi.GetBondShortNameEn().c_str())) {
          if (!bAscend)
            *field = 0;
          else
            *field = (char)0xFF;
          break;
        }
        StringCopy(field, capcity, bi.GetBondShortNameEn().c_str());
        break;
      case VEXPIRY_DATE: {
        string sRemainDate = bi.GetRemainDate();
        double dDay1 = CBondContainer::CalcRemainingDay(sRemainDate);
        if (sRemainDate.find("D") == string::npos)  // 365D小于366D小于1Y
        {
          dDay1 += 1.1;
        }
        if (dDay1 == -1) {
          if (!bAscend)
            dDay1 = -1;
          else
            dDay1 = MAX_VAL;
        }
        *((double*)field) = dDay1;
      } break;
      case VBUYVOL:  // kSortTypeDouble,compare_buy_volumn
      {
        REPORT* preport = CBondUtil::GetCompanyInfoById(brokerid, key);
        double Volume1 = atof(
            preport->m_bidinfo.m_sVolume);  // modified XW20150410 atio->atof
        if (strcmp(preport->m_bidinfo.m_price_status, "0") == 0) Volume1 = 0;
        *((double*)field) = Volume1;
      } break;
      case VBUYVOL_SETTLEMENT: {
        REPORT* preport = CBondUtil::GetCompanyInfoByIdAndSettlement(
            brokerid, key, btPriceFilter);
        double Volume1 = atof(preport->m_bidinfo.m_sVolume);
        if (strcmp(preport->m_bidinfo.m_price_status, "0") == 0) {
          if (!bAscend)
            Volume1 = 0;
          else
            Volume1 = MAX_VAL;
        }
        *((double*)field) = Volume1;
      } break;
      case VBUYPRICE:  // kSortTypeDouble,compare_buy_price,
        *((double*)field) = CBondUtil::GetBuyPrice(key);
        break;
      case VBUYPRICE_SETTLEMENT:  // kSortTypeDouble,compare_buy_price,
        *((double*)field) =
            CBondUtil::GetBuyPriceBySettlement(key, btPriceFilter, bAscend);
        break;
      case VBUYNETPRICE:  // kSortTypeDouble,compare_buy_price,
        *((double*)field) = CBondUtil::GetBuyNetPrice(key);
        break;
      case VBUYNETPRICE_SETTLEMENT:  // kSortTypeDouble,compare_buy_price,
        *((double*)field) =
            CBondUtil::GetBuyNetPriceBySettlement(key, btPriceFilter, bAscend);
        break;
      case VBUYFULLPRICE_SETTLEMENT:
        *((double*)field) =
            CBondUtil::GetBuyFullPriceBySettlement(key, btPriceFilter, bAscend);
        break;
      case VSELLVOL: {
        REPORT* preport = CBondUtil::GetCompanyInfoById(brokerid, key);
        double Volume1 = atof(
            preport->m_askinfo.m_sVolume);  // modified XW20150410 atio->atof
        if (strcmp(preport->m_askinfo.m_price_status, "0") == 0) Volume1 = 0;
        *((double*)field) = Volume1;
      } break;
      case VSELLVOL_SETTLEMENT: {
        REPORT* preport = CBondUtil::GetCompanyInfoByIdAndSettlement(
            brokerid, key, btPriceFilter);
        double Volume1 = atof(
            preport->m_askinfo.m_sVolume);  // modified XW20150410 atio->atof
        if (strcmp(preport->m_askinfo.m_price_status, "0") == 0) {
          if (!bAscend)
            Volume1 = 0;
          else
            Volume1 = MAX_VAL;
        }
        *((double*)field) = Volume1;
      } break;
      case VSELLPRICE:
        *((double*)field) = CBondUtil::GetSellPrice(key);
        break;
      case VSELLPRICE_SETTLEMENT:
        *((double*)field) =
            CBondUtil::GetSellPriceBySettlement(key, btPriceFilter, bAscend);
        break;
      case VSELLNETPRICE:  // kSortTypeDouble,compare_buy_price,
        *((double*)field) = CBondUtil::GetSellNetPrice(key);
        break;
      case VSELLNETPRICE_SETTLEMENT:  // kSortTypeDouble,compare_buy_price,
        *((double*)field) =
            CBondUtil::GetSellNetPriceBySettlement(key, btPriceFilter, bAscend);
        break;
      case VSELLFULLPRICE_SETTLEMENT:
        *((double*)field) = CBondUtil::GetSellFullPriceBySettlement(
            key, btPriceFilter, bAscend);
        break;
      case VMODIFY_TIME:  // kSortTypeDouble,compare_modify_time
        *((double*)field) = CBondUtil::GetModifyTime(key);
        break;
      case VMODIFY_TIME_SETTLEMENT:  // kSortTypeDouble,compare_modify_time
        *((double*)field) =
            CBondUtil::GetModifyTimeBySettlement(key, btPriceFilter) == 0
                ? (bAscend ? MAX_VAL : 0)
                : CBondUtil::GetModifyTimeBySettlement(key, btPriceFilter);
        break;

        /************综合最优排序************/
      case V_MIXEDBP_BUYVOL:  // kSortTypeDouble,compare_buy_volumn
      {
        REPORT* preport = CBondUtil::GetMixedBestPrice(key, btPriceFilter);
        double Volume1 = atof(
            preport->m_bidinfo.m_sVolume);  // modified XW20150410 atio->atof
        if (strcmp(preport->m_bidinfo.m_price_status, "0") == 0) {
          if (!bAscend)
            Volume1 = 0;
          else
            Volume1 = MAX_VAL;
        }
        *((double*)field) = Volume1;
      } break;
      case V_MIXEDBP_BUYPRICE:  // kSortTypeDouble,compare_buy_price,
        *((double*)field) =
            CBondUtil::GetMixedBPBuyPrice(key, btPriceFilter, bAscend);
        break;
      case V_MIXEDBP_BUYNETPRICE:  // kSortTypeDouble,compare_buy_price,
        *((double*)field) =
            CBondUtil::GetMixedBPBuyNetPrice(key, btPriceFilter, bAscend);
        break;
      case V_MIXEDBP_BUYFULLPRICE:  // Bid.NetPrice
        *((double*)field) =
            CBondUtil::GetMixedBPBuyFullPrice(key, btPriceFilter, bAscend);
        break;
      case V_MIXEDBP_SELLVOL: {
        REPORT* preport = CBondUtil::GetMixedBestPrice(key, btPriceFilter);
        double Volume1 = atof(
            preport->m_askinfo.m_sVolume);  // modified XW20150410 atio->atof
        if (strcmp(preport->m_askinfo.m_price_status, "0") == 0) {
          if (!bAscend)
            Volume1 = 0;
          else
            Volume1 = MAX_VAL;
        }
        *((double*)field) = Volume1;
      } break;
      case V_MIXEDBP_SELLPRICE:
        *((double*)field) =
            CBondUtil::GetMixedBPSellPrice(key, btPriceFilter, bAscend);
        break;
      case V_MIXEDBP_SELLNETPRICE:
        *((double*)field) =
            CBondUtil::GetMixedBPSellNetPrice(key, btPriceFilter, bAscend);
        break;
      case V_MIXEDBP_SELLFULLPRICE:
        *((double*)field) =
            CBondUtil::GetMixedBPSellFullPrice(key, btPriceFilter, bAscend);
        break;
      case V_MIXEDBP_MODIFY_TIME:  // kSortTypeDouble,compare_modify_time
      {
        double t = CBondUtil::GetMixedBPModifyTime(key, btPriceFilter);
        *((double*)field) = t < 1e-5 ? (bAscend ? MAX_VAL : 0) : t;
        break;
      }
      case V_MIXEDBP_BID_CDC:  // kSortTypeDouble,compare_bid_estprice,bid-估值
        *((double*)field) =
            (bi.IsCDCAuthValid())
                ? ToSpecialFloat(
                      GetBidEstPriceMixedBP(key, true, btPriceFilter), bAscend)
                : (bAscend ? MAX_VAL : MIN_UNAUTH_VALUE);
        break;
      case V_MIXEDBP_CDC_OFR:  // kSortTypeDouble,compare_estprice_ofr,估值-ofr
        *((double*)field) =
            (bi.IsCDCAuthValid())
                ? ToSpecialFloat(
                      GetEstPriceOfrMixedBP(key, true, btPriceFilter), bAscend)
                : (bAscend ? MAX_VAL : MIN_UNAUTH_VALUE);
        break;
      case V_MIXEDBP_BID_CSI:  // kSortTypeDouble,compare_bid_estprice,bid-估值
        *((double*)field) =
            (bi.IsCDCAuthValid())
                ? ToSpecialFloat(GetBidCsiPriceMixedBP(key, btPriceFilter),
                                 bAscend)
                : (bAscend ? MAX_VAL : MIN_UNAUTH_VALUE);
        break;
      case V_MIXEDBP_CSI_OFR:  // kSortTypeDouble,compare_estprice_ofr,估值-ofr
        *((double*)field) =
            (bi.IsCDCAuthValid())
                ? ToSpecialFloat(GetCsiPriceOfrMixedBP(key, btPriceFilter),
                                 bAscend)
                : (bAscend ? MAX_VAL : MIN_UNAUTH_VALUE);
        break;
        /************综合最优排序 end ************/
      case VRATING:  // kSortTypeInt,compare_rating,CompareRankWithIssuerRating
      case VISSUERRATING:
        if (IsEmpty(bi.GetIssuerRatingEx())) {
          if (!bAscend)
            *((int*)field) = -1;
          else
            *((int*)field) = INT_MAX;
          break;
        }
        *((int*)field) =
            RatingRankManager::Get().GetRatingRank(bi.GetIssuerRatingEx());
        break;
      case VCDCRATING:  // kSortTypeInt,compare_rating,CompareRankWithIssuerRating
        if (SSUserAccountManager::instance().HasAuthOfCDC()) {
          if (IsEmpty(bi.GetCDCRating()) ||
              strcmp(bi.GetCDCRating(), "CCL") == 0) {
            if (!bAscend)
              *((int*)field) = -1;
            else
              *((int*)field) = INT_MAX;
            break;
          }
          *((int*)field) =
              RatingRankManager::Get().GetRatingRank(bi.GetCDCRating());
        } else {
          if (!bAscend)
            *((int*)field) = -1;
          else
            *((int*)field) = INT_MAX;
        }
        break;
      case VCSIRATING:  // kSortTypeInt,compare_rating,CompareRankWithIssuerRating
        if (SSUserAccountManager::instance().HasAuthOfCSI()) {
          if (IsEmpty(bi.GetCSIRating()) ||
              strcmp(bi.GetCSIRating(), "CCL") == 0) {
            if (!bAscend)
              *((int*)field) = -1;
            else
              *((int*)field) = INT_MAX;
            break;
          }
          *((int*)field) =
              RatingRankManager::Get().GetRatingRank(bi.GetCSIRating());
        } else {
          if (!bAscend)
            *((int*)field) = -1;
          else
            *((int*)field) = INT_MAX;
        }
        break;
      case VCBRRATING:  // kSortTypeInt,compare_rating,CompareRankWithIssuerRating
        if (SSUserAccountManager::instance().HasAuthOfCBR()) {
          if (IsEmpty(bi.GetCBRRating()) ||
              strcmp(bi.GetCBRRating(), "CCL") == 0) {
            if (!bAscend)
              *((int*)field) = -1;
            else
              *((int*)field) = INT_MAX;
            break;
          }
          *((int*)field) =
              RatingRankManager::Get().GetRatingRank(bi.GetCBRRating());
        } else {
          if (!bAscend)
            *((int*)field) = -1;
          else
            *((int*)field) = INT_MAX;
        }
        break;
      case VESTBPRICEPRE:  // kSortTypeDouble,compare_estb_price;
      {
        int optType = CBondCDCPriceInfo::est_type_invalid;
        *((double*)field) =
            (bi.IsCDCAuthValid())
                ? ToSpecialFloat(
                      CBondCDCPriceInfo::instance()
                          .GetCDCPriceYesterday(
                              optType, true, i,
                              CBondCDCPriceInfo::price_type_yield, false)
                          .c_str(),
                      bAscend)
                : (bAscend ? MAX_VAL : MIN_UNAUTH_VALUE);
        break;
      }
      case VESTBPRICETODAY:  // kSortTypeDouble,compare_estb_price;
      {
        int optType = CBondCDCPriceInfo::est_type_invalid;
        *((double*)field) =
            (bi.IsCDCAuthValid())
                ? ToSpecialFloat(
                      CBondCDCPriceInfo::instance()
                          .GetCDCPriceToday(optType, true, i,
                                            CBondCDCPriceInfo::price_type_yield,
                                            false)
                          .c_str(),
                      bAscend)
                : (bAscend ? MAX_VAL : MIN_UNAUTH_VALUE);
        break;
      }
      case VESTBCLEPRICE:  // kSortTypeDouble,compare_estb_cprice
      {
        int optType = CBondCDCPriceInfo::est_type_invalid;
        *((double*)field) =
            (bi.IsCDCAuthValid())
                ? ToDashFloat(CBondCDCPriceInfo::instance()
                                  .GetCDCPriceYesterday(
                                      optType, true, i,
                                      CBondCDCPriceInfo::price_type_clean,
                                      false)
                                  .c_str())
                : MIN_UNAUTH_VALUE;
        break;
      }
      case VBOND_TYPE: /*sort_bond_type*/
        break;
      case VBUYCLEPRICE: /*sort_bcle_price*/
        break;
      case VSELLCLEPRICE: /*sort_scle_price*/
        break;
      case VMATURITY_DATE: /*sort_maturity_date*/
        break;
      case VCROSSMARKET: /*sort_cross_market*/
        break;
      case VBROKERKEY:
        *((int*)field) = atoi(brokerid.c_str());
        break;
      case VBONDRATING:
        if (IsEmpty(bi.GetBondRating())) {
          if (!bAscend)
            *((int*)field) = -1;
          else
            *((int*)field) = INT_MAX;
          break;
        }
        *((int*)field) =
            RatingRankManager::Get().GetRatingRank(bi.GetBondRating());
        break;
      case INDICATIVE_PRICE: {
        REPORT* preport = CBondUtil::GetCompanyInfoById(brokerid, key);
        *((double*)field) = atof(preport->m_indx_info.m_price);
      } break;
      case VTKNPRICE:  // compare_taken_price
      {
        *((double*)field) = GetTknPrice(key, bi, batchMode, 0);
      } break;
      case BSVTKPRICE: {
        REPORT* preport = CBondUtil::GetCompanyInfoById(brokerid, key);
        *((double*)field) = atof(preport->m_tradePrice);
      } break;
      case PLANNED_ISSURE_AMOUNT:  // compare_planned_issure_amount,计划发行量(亿)
        *((double*)field) = bi.GetPlannedIssueAmount();
        break;
      case BID_LIMIT:  // kSortTypeBidLimit,compare_bid_limit,投标区间
      {
        const char* strBottom_i = bi.GetBidLimitBottom();
        const char* strTop_i = bi.GetBidLimitTop();
        double dBottom_i = strBottom_i == NULL ? 0 : atof(strBottom_i);
        double dTop_i = strTop_i == NULL ? 0 : atof(strTop_i);
        *((double*)field) = dBottom_i;
        *((double*)field + 1) = dTop_i;
      } break;
      case AUCTION_LIMIT:  // compare_auction_limit,标位区间
      {
        const char* strBottom_i = bi.GetAuctionFlr();
        const char* strTop_i = bi.GetAuctionCap();
        double dBottom_i = strBottom_i == NULL ? 0 : atof(strBottom_i);
        double dTop_i = strTop_i == NULL ? 0 : atof(strTop_i);
        *((double*)field) = dBottom_i;
        *((double*)field + 1) = dTop_i;
      } break;
      case ISSUE_START_DATE:  //: kSortTypeInt,compare_issue_start_date,发行日
        *((int*)field) =
            bi.GetIssueStartDate() ? atoi(bi.GetIssueStartDate()) : 0;
        break;
      case PAYMENT_DATE:  // kSortTypeInt,compare_payment_date,缴款日
        *((int*)field) = bi.GetPaymentDate() ? atoi(bi.GetPaymentDate()) : 0;
        break;
      case LISTED_DATE:  // kSortTypeInt,compare_listed_date,上市日
        *((int*)field) = bi.GetPaymentDate() ? atoi(bi.GetListDate()) : 0;
        break;
      case INSTITUTION_TYPE:  // kSortTypeInt,compare_institution_type,企业类型
        *((int*)field) = GetInstitutionSortId(bi.GetInstitutionType());
        break;
      case ANNOUNCE_DATE:  // compare_announce_date
        *((int*)field) = bi.GetAnnounceDate() ? atoi(bi.GetAnnounceDate()) : 0;
        break;
      case COUPON_RATE: {
        const char* rate = bi.GetCouponRateCurrent();
        *((double*)field) = (!IsEmpty(rate)) ? atof(rate) : (-999);
      } break;
      case MATURITY_TERM_END:  // compare_MaturityTerm_End,期限m_sMaturityTerm,
      case TERM_TO_MATURITY:   // MATURITY_TERM
      {
        if (IsEmpty(bi.GetTermToMaturity())) {
          if (!bAscend)
            *((int*)field) = -1;
          else
            *((int*)field) = INT_MAX;
          break;
        }
        *((int*)field) = i;
      } break;
      case AREA:  // compare_area,地区
        StringCopy(field, capcity, bi.GetArea());
        break;
      case SECTOR:  // compare_sector,行业
        StringCopy(field, capcity, bi.GetSwSector());
        break;
      case INTEREST_START_DATE:  // kSortTypeString,compare_interest_start_date,起息日
        StringCopy(field, capcity, bi.GetInterestStartDate());
        break;
      case kInstitutionName:  // kSortTypeString,compare_institution_name,机构简称
        StringCopy(field, capcity, bi.GetInstitutionShortName());
        break;
      case kIssueEndTime:  // kSortTypeString,compare_issue_end_time,截标时间
      {
        const char* start = bi.GetIssueStartDate();
        int len = strlen(start);
        StringCopy(field, capcity, start);
        StringCopy(field + len, capcity - len, bi.GetIssueEndTime());
      } break;
      case kActualIssureAmount:  // kSortTypeDouble,,compare_actual_issure_amount,实际发行量
        *((double*)field) =
            CBondContainer::instance().GetBondActualIssueAmount(i) < 0.0001
                ? (bAscend ? MAX_VAL : -1)
                : CBondContainer::instance().GetBondActualIssueAmount(i);
        break;
      case kIssuerAmount:  // kSortTypeDouble,compare_issure_amount发行量:优先取实际发行量，无值时取计划发行量
      {
        double actual = bi.GetActualIssueAmount();
        if ((actual - 0.000) < 1.0f) actual = bi.GetPlannedIssueAmount();
        *((double*)field) = actual;
      } break;
      case kCouponType:  // kSortTypeString,compare_coupon_type,利率方式
        StringCopy(field, capcity, bi.GetCouponTypeName());
        break;
      case kRateType:  //  票面  add  by lbl
      {
        /*	static std::string strTemp;
                if (Item.strText == _T("FIXED"))
                {
                        if (m_isEnglish) {
                                Item.strText = _T("Fixed-rate");
                        }
                        else
                                Item.strText = _T("固息");
                }*/
        if (IsEmpty(bi.GetRateType())) {
          if (!bAscend)
            *field = 0;
          else
            *field = (char)0xFF;
          break;
        }
        StringCopy(field, capcity, bi.GetRateType());
        break;
      }
      case kDuration:  // kSortTypeDouble,compare_duration,久期
      {
        int optType;
        if (bi.IsCDCAuthValid())
          *((double*)field) = ToSpecialFloat(
              CBondCDCPriceInfo::instance()
                  .GetCDCPriceYesterday(optType, true, i,
                                        CBondCDCPriceInfo::price_type_duration,
                                        false)
                  .c_str(),
              bAscend);
        else
          *((double*)field) = bAscend ? MAX_VAL : MIN_UNAUTH_VALUE;
        break;
      }
      case kBid_EstPrice:  // kSortTypeDouble,compare_bid_estprice,bid-估值
        *((double*)field) = (bi.IsCDCAuthValid())
                                ? ToDashFloat(GetBidEstPrice(i, brokerid, true))
                                : MIN_UNAUTH_VALUE;
        break;
      case kBid_EstPrice_Settlement:  // kSortTypeDouble,compare_bid_estprice,bid-估值
        *((double*)field) =
            (bi.IsCDCAuthValid())
                ? ToSpecialFloat(GetBidEstPriceBySettlement(i, brokerid, true,
                                                            btPriceFilter),
                                 bAscend)
                : (bAscend ? MAX_VAL : MIN_UNAUTH_VALUE);
        break;
      case kEstPrice_Ofr:  // kSortTypeDouble,compare_estprice_ofr,估值-ofr
        *((double*)field) = (bi.IsCDCAuthValid())
                                ? ToDashFloat(GetEstPriceOfr(i, brokerid, true))
                                : MIN_UNAUTH_VALUE;
        break;
      case kEstPrice_Ofr_Settlement:  // kSortTypeDouble,compare_estprice_ofr,估值-ofr
        *((double*)field) =
            (bi.IsCDCAuthValid())
                ? ToSpecialFloat(GetEstPriceOfrBySettlement(i, brokerid, true,
                                                            btPriceFilter),
                                 bAscend)
                : (bAscend ? MAX_VAL : MIN_UNAUTH_VALUE);
        break;
      case kOutlook:  // kSortTypeInt,compare_outlook,展望
        if (IsEmpty(bi.GetOutlookName()) ||
            !strcmp(bi.GetOutlookName(), "无")) {
          if (!bAscend)
            *((int*)field) = -99;
          else
            *((int*)field) = INT_MAX;
          break;
        }
        *((int*)field) = bi.GetOutlookLevel();
        break;
      case kIssuerPeriod:  // kSortTypeIssuerPeriod,compare_IssuePeriod,发行时间,募集时间段,6294
                           // 复杂----------------------------------------------
      {
        *((IssuePeriod*)field) = GetIssuePeriodSortId(i);
      } break;

      case kInstitutionFullName:  // kSortTypeString,compare_institution_fullname,发行人机构全称
        StringCopy(field, capcity, bi.GetInstitutionFullName());
        break;
      case ISSUE_DATE_IsuPeriod:  // kSortTypeInt,compare_issue_start_date_IssuePeriod,发行日,募集时间段
      {
        const char* strDate = bi.GetIssueStartDate();
        *((int*)field) = (strDate == NULL || !IsEmpty(bi.GetIssuePeriod()))
                             ? 0
                             : atoi(strDate);
      } break;
      case PAYMENT_DATE_IsuPeriod:  // kSortTypeInt,compare_payment_date_IssuePeriod???,缴款日,募集时间段
      {
        const char* strDate = bi.GetPaymentDate();
        *((int*)field) = (strDate == NULL) ? 0 : atoi(strDate);
      } break;
      case LISTED_DATE_IsuPeriod:  // kSortTypeInt,compare_listed_date_IssuePeriod,上市日,募集时间段
      {
        const char* strDate = bi.GetListDate();
        *((int*)field) = (strDate == NULL || !IsEmpty(bi.GetIssuePeriod()))
                             ? 0
                             : atoi(strDate);
      } break;
      case ANNOUNCE_DATE_IsuPeriod:  // kSortTypeInt,compare_announce_date_IssuePeriod,公告日,募集时间段
      {
        const char* strDate = bi.GetAnnounceDate();
        *((int*)field) = (strDate == NULL || !IsEmpty(bi.GetIssuePeriod()))
                             ? 0
                             : atoi(strDate);
      } break;
      case INTEREST_DATE_IsuPeriod:  // kSortTypeString,compare_interest_start_date_IssuePeriod,起息日，募集时间段
        StringCopy(
            field, capcity,
            !IsEmpty(bi.GetIssuePeriod()) ? "--" : bi.GetInterestStartDate());
        break;
      case kIssueRate:  // kSortTypeDouble,compare_issue_rate,发行利率
      {
        const char* pRate = bi.GetIssueRate();
        *((double*)field) = (!IsEmpty(pRate)) ? atof(pRate) : (-999);
      } break;
      case kConvRate:  // kSortTypeDouble,compare_conversion_rate,质押比例
        if (IsEmpty(bi.GetConversionRate())) {
          if (!bAscend)
            *((double*)field) = -1;
          else
            *((double*)field) = MAX_VAL;
          break;
        }
        *((double*)field) = atof(bi.GetConversionRate());
        break;
      case kTknPrice:  // compare_clean_price,成交净价
        *((double*)field) = GetTknPrice(key, bi, batchMode, 1, bAscend);
        break;
      case kCleanPriceDiv:  // compare_clean_price_div,净价偏离度
        *((double*)field) = GetCleanPriceDiv(key, i, bi, batchMode);
        break;
      case kTknYield:  // compare_tkn_yield,成交收益率
        *((double*)field) = GetYield(key, bi, batchMode);
        break;
      case kYieldDiv:  // compare_yield_div,收益率偏离度
        *((double*)field) = GetYieldDiv(key, i, bi, batchMode);
        break;
      case kCouponRate:  // kSortTypeDouble,compare_coupon_rate_ex,票面利率
      {
        const char* pRate = bi.GetCouponRateCurrent();
        *((double*)field) =
            (!IsEmpty(pRate)) ? atof(pRate) : (bAscend ? MAX_VAL : -999);
      } break;
      case kCsiVal:  // kSortTypeDouble,compare_csival,中证估值
        if (m_csiauth) {
          *((double*)field) = CBondCSInfo::instance().GetCsiYieldForSort(
                                  bi.GetCombBondKey()) == _INVALID_CSI_VALUE
                                  ? (bAscend ? MAX_VAL : _INVALID_CSI_VALUE)
                                  : CBondCSInfo::instance().GetCsiYieldForSort(
                                        bi.GetCombBondKey());
        } else {
          *((double*)field) = bAscend ? MAX_VAL : _INVALID_CSI_VALUE;
        }
        break;
      case kCsiCleanPrice:  // kSortTypeDouble,compare_csi_clean_price,中证净价
        if (m_csiauth) {
          *((double*)field) =
              CBondCSInfo::instance().GetCsiCleanPriceForSort(
                  bi.GetCombBondKey()) == _INVALID_CSI_VALUE
                  ? (bAscend ? MAX_VAL : _INVALID_CSI_VALUE)
                  : CBondCSInfo::instance().GetCsiCleanPriceForSort(
                        bi.GetCombBondKey());
        } else {
          *((double*)field) = bAscend ? MAX_VAL : _INVALID_CSI_VALUE;
        }
        break;
      case kCsiFullPrice:  // 中证全价
        if (m_csiauth) {
          *((double*)field) =
              CBondCSInfo::instance().GetCsiFullPriceForSort(
                  bi.GetCombBondKey()) == _INVALID_CSI_VALUE
                  ? (bAscend ? MAX_VAL : _INVALID_CSI_VALUE)
                  : CBondCSInfo::instance().GetCsiFullPriceForSort(
                        bi.GetCombBondKey());
        } else {
          *((double*)field) = bAscend ? MAX_VAL : _INVALID_CSI_VALUE;
        }
        break;
      case kSHEX_SHCOL_SOURCE: {
        bool isExchange = true;
        const char* sCode = bi.GetCombBondCode();
        int nCorpID = atoi(brokerid.c_str());
        if (nCorpID == 111)  // 上证固收
        {
          isExchange = false;
        }
        if (CMarketMakeTarget::instance().IsMarkertMakeTarget(sCode)) {
          if (bi.is_interest_bond()) {
            if (isExchange) {  // 交易所利率债显示做市
              *((int*)field) = 122;
            } else {
              *((int*)field) = 121;
            }
          } else {
            if (isExchange) {
              *((int*)field) = 120;
            } else {  // 上证固收信用债显示做市
              *((int*)field) = 122;
            }
          }
        } else if (isExchange) {
          *((int*)field) = 120;
        } else {
          *((int*)field) = 121;  // 上证固收;
        }
        break;
      }
      case kCdcCleanPrice:  // kSortTypeDouble,compare_cdc_clean_price,中债净价
      {
        int optType;
        *((double*)field) =
            (bi.IsCDCAuthValid())
                ? ToSpecialFloat(
                      CBondCDCPriceInfo::instance()
                          .GetCDCPriceYesterday(
                              optType, true, i,
                              CBondCDCPriceInfo::price_type_clean, false)
                          .c_str(),
                      bAscend)
                : (bAscend ? MAX_VAL : MIN_UNAUTH_VALUE);
        break;
      }
      case kCdcFullPrice:  // 中债全价
      {
        int optType;
        *((double*)field) =
            (bi.IsCDCAuthValid())
                ? ToSpecialFloat(
                      CBondCDCPriceInfo::instance()
                          .GetCDCPriceYesterday(
                              optType, true, i,
                              CBondCDCPriceInfo::price_type_full, false)
                          .c_str(),
                      bAscend)
                : (bAscend ? MAX_VAL : MIN_UNAUTH_VALUE);
        break;
      }
      case kSHEX_TKN_CDCYield:  // 成交-中债
      {
        if (!bi.IsCDCAuthValid()) {
          *((double*)field) = bAscend ? MAX_VAL : MIN_UNAUTH_VALUE;
          break;
        }

        int exec = -1;
        double priceGap = CBondCDCPriceInfo::instance().GetYesterdayCDCPriceGap(
            true, key.m_nIndex, CBondCDCPriceInfo::price_type_yield, true, "",
            INVALID_CDC_VALUE, exec);
        std::string strPriceGap = std::to_string(priceGap);
        if ((priceGap + 1e6) <= 1e-6) {
          strPriceGap = "--";
        }
        *((double*)field) = ToSpecialFloat(strPriceGap.c_str(), bAscend);
        break;
      }
      case kSHEX_TKN_CDCFullPrice:  // 成交-中债
      {
        if (!bi.IsCDCAuthValid()) {
          *((double*)field) = bAscend ? MAX_VAL : MIN_UNAUTH_VALUE;
          break;
        }

        int exec = -1;
        double priceGap =
            CBondCDCPriceInfo::instance().GetYesterdayCDCCleanPriceGap(
                true, key.m_nIndex, CBondCDCPriceInfo::price_type_full, true,
                "", INVALID_CDC_VALUE, exec);
        std::string strPriceGap = std::to_string(priceGap);
        if ((priceGap + 1e6) <= 1e-6) {
          strPriceGap = "--";
        }
        *((double*)field) = ToSpecialFloat(strPriceGap.c_str(), bAscend);
        break;
      }
      case kSHEX_TKN_CSIYield:  // 成交-中证
      {
        if (!m_csiauth) {
          *((double*)field) = bAscend ? MAX_VAL : MIN_UNAUTH_VALUE;
          break;
        }

        int exec = -1;
        *((double*)field) =
            ToSpecialFloat(FmtDealMinusCSI(bi.GetCombBondKey(), "",
                                           CBondCSInfo::price_type_yield, exec)
                               .c_str(),
                           bAscend);
        break;
      }
      case kSHEX_TKN_CSIFullPrice:  // 成交-中证
      {
        if (!m_csiauth) {
          *((double*)field) = bAscend ? MAX_VAL : MIN_UNAUTH_VALUE;
          break;
        }

        int exec = -1;
        *((double*)field) =
            ToSpecialFloat(FmtDealMinusCSI(bi.GetCombBondKey(), "",
                                           CBondCSInfo::price_type_full, exec)
                               .c_str(),
                           bAscend);
        break;
      }
      case kOptionType:  // kSortTypeString,compare_option_type,含权类型
        if (IsEmpty(bi.GetOptionType())) {
          if (!bAscend)
            *field = 0;
          else
            *field = (char)0xFF;
          break;
        }
        StringCopy(field, capcity, bi.GetOptionType());
        break;
      case kOptionDate:  // kSortTypeDouble,compare_option_date,行权日
        if (IsEmpty(bi.GetOptionDate())) {
          if (!bAscend)
            *((double*)field) = -1;
          else
            *((double*)field) = MAX_VAL;
          break;
        }
        *((double*)field) = atof(bi.GetOptionDate());
        break;
      case kCsi_Cdc:  // kSortTypeDouble,compare_csi_cdc中证-中债
        *((double*)field) =
            (bi.IsCDCAuthValid())
                ? ToSpecialFloat(GetCsi_CdcPrice(i, true), bAscend)
                : (bAscend ? MAX_VAL : MIN_UNAUTH_VALUE);
        break;
      case kCrossMarket:  // kSortTypeChar,compare_cross_market,跨市场
        if (bi.GetCrossmarket() == 0 || bi.GetCrossmarket() == '\0') {
          if (!bAscend)
            *((double*)field) = -1;
          else
            *((double*)field) = MAX_VAL;
          break;
        }
        *((char*)field) = bi.GetCrossmarket();
        break;
      case kIndustry:  // kSortTypeString,行业
        if (IsEmpty(bi.GetSwSector())) {
          if (!bAscend)
            *field = 0;
          else
            *field = (char)0xFF;
          break;
        }
        StringCopy(field, capcity, bi.GetSwSector());
        break;
      case kIndustryEn:
        if (IsEmpty(bi.GetSwSector(true))) {
          if (!bAscend)
            *field = 0;
          else
            *field = (char)0xFF;
          break;
        }
        StringCopy(field, capcity, bi.GetSwSector(true));
        break;
      case kRatingAgency:  // kSortTypeString,评级机构简称
        if (IsEmpty(bi.GetRatingInstitutionShortName())) {
          if (!bAscend)
            *field = 0;
          else
            *field = (char)0xFF;
          break;
        }
        StringCopy(field, capcity, bi.GetRatingInstitutionShortName());
        break;
      case VBondType:  // VBondType 债券类型
        *((int*)field) = CBondTypeMap::instance().GetTypeEm(bi.GetBondSubType(),
                                                            bi.GetEntCor());
        break;
      case VBondIssuer:  // VBondIssuer 债券发行人
        if (IsEmpty(bi.GetIssuerCode())) {
          if (!bAscend)
            *field = 0;
          else
            *field = (char)0xFF;
          break;
        }
        StringCopy(field, capcity, bi.GetIssuerCode());
        break;
      case kBondGuarantor:  // 担保人
      case kBondGuarantorEn: {
        std::string sName("");
        auto pIssuer =
            CQBIssuerInfo::instance().GetIssuerInfo(bi.GetWarranter());
        if (pIssuer) {
          if (col == kBondGuarantor) {
            if (IsEmpty(pIssuer->field((int)kIssuerInfo::Full_Name_C))) {
              if (!bAscend)
                *field = 0;
              else
                *field = (char)0xFF;
              break;
            }
            StringCopy(field, capcity,
                       pIssuer->field((int)kIssuerInfo::Full_Name_C));
          } else {
            if (IsEmpty(pIssuer->field((int)kIssuerInfo::Full_Name_E))) {
              if (!bAscend)
                *field = 0;
              else
                *field = (char)0xFF;
              break;
            }
            StringCopy(field, capcity,
                       pIssuer->field((int)kIssuerInfo::Full_Name_E));
          }
        } else {
          if (!bAscend)
            *field = 0;
          else
            *field = (char)0xFF;
        }
        break;
      }
      case kBondLiquidity:  // 债券流动性
      {
        xQBBondLiquidityUnit unit;
        if (CBondLiquidity::instance().GetLiquidity(i, unit)) {
          *((double*)field) = atof(unit.m_liquid);
        } else {
          if (!bAscend)
            *((double*)field) = -1;
          else
            *((double*)field) = MAX_VAL;
        }
        break;
      }
      case kIssuerLiquidity:  // 主体流动性
      {
        xQBIssuerLiquidityUnit unit;
        if (CIssuerLiquidity::instance().GetLiquidity(i, unit)) {
          *((double*)field) = atof(unit.m_liquid);
        } else {
          if (!bAscend)
            *((double*)field) = -1;
          else
            *((double*)field) = MAX_VAL;
        }
        break;
      }
      case kOutstandingAmount:  // 债券余额
        *((double*)field) = bi.GetOutstandingAmount() < 0.0001
                                ? (bAscend ? MAX_VAL : -1)
                                : bi.GetOutstandingAmount();
        break;
      case kBid_CsiVal:  // kSortTypeDouble,bid-中证估值
        *((double*)field) = ToDashFloat(GetBidCsiPrice(i, brokerid));
        break;
      case kBid_CsiVal_Settlement:
        *((double*)field) = ToSpecialFloat(
            GetBidCsiPriceBySettlement(i, brokerid, btPriceFilter), bAscend);
        break;
      case kCsiVal_Ofr:  // kSortTypeDouble,中证估值-ofr
        *((double*)field) = ToDashFloat(GetCsiPriceOfr(i, brokerid));
        break;
      case kCsiVal_Ofr_Settlement:  // kSortTypeDouble,中证估值-ofr
        *((double*)field) = ToSpecialFloat(
            GetCsiPriceOfrBySettlement(i, brokerid, btPriceFilter), bAscend);
        break;
      case kMaturityDate:
        if (IsEmpty(bi.GetMaturityDate())) {
          if (!bAscend)
            *((double*)field) = -1;
          else
            *((double*)field) = MAX_VAL;
          break;
        }
        StringCopy(field, capcity, bi.GetMaturityDate());
        break;
      case kMaturityDate_IsuPeriod:  //
        StringCopy(field, capcity,
                   !IsEmpty(bi.GetIssuePeriod()) ? "" : bi.GetMaturityDate());
        break;
      case kDeal_Cdc:  // 成交-中债
        *((double*)field) = (bi.IsCDCAuthValid())
                                ? GetTakenCdc(key, i, true, bAscend)
                                : (bAscend ? MAX_VAL : MIN_UNAUTH_VALUE);
        break;
      case kDeal_Csi:  // 成交-中证
        *((double*)field) = m_csiauth ? GetTakenCsi(key, bi, bAscend)
                                      : (bAscend ? MAX_VAL : MIN_UNAUTH_VALUE);
        break;
      case kCFETS_Buyer:  // CFETS买方
      {
        // 截断风险
        CFETSQUOTE* pCfetsQuote =
            CBondUtil::GetCFETSQuoteById(key, btPriceFilter);
        if (pCfetsQuote)
          StringCopy(field, capcity, pCfetsQuote->m_BidCompanyName.c_str());
        break;
      }
      case kCFETS_BidFull:   // CFETS 全价 bid
      case kCFETS_BidVol:    // CFETS bid 量
      case kCFETS_BidClean:  // CFETS 净价 bid
      case kCFETS_Bid:       // CFETS  bid
      case kCFETS_Ofr:       // CFETS  ofr
      case kCFETS_OfrClean:  // CFETS 净价ofr
      case kCFETS_OfrVol:    // CFETS ofr 量
      case kCFETS_OfrFull:   // CFETS 全价 ofr
      {
        *((double*)field) =
            CBondUtil::GetCFETSRawDouble(key, col, btPriceFilter);
        break;
      }
      case kCFETS_Seller:  // CFETS 卖方
      {
        CFETSQUOTE* pCfetsQuote =
            CBondUtil::GetCFETSQuoteById(key, btPriceFilter);
        if (pCfetsQuote)
          StringCopy(field, capcity, pCfetsQuote->m_OfrCompanyName.c_str());
        break;
      }
      case kCFETS_Bid_CdcVal:  // CFETS bid - 中债估值
      {
        CFETSQUOTE* pCfetsQuote =
            CBondUtil::GetCFETSQuoteById(key, btPriceFilter);
        *((double*)field) =
            (bi.IsCDCAuthValid())
                ? ToDashFloat(GetBidEstPrice(pCfetsQuote, &bi, i, true))
                : MIN_UNAUTH_VALUE;
        break;
      }
      case kCFETS_CdcVal_Ofr:  // CFETS 中债估值 - ofr
      {
        CFETSQUOTE* pCfetsQuote =
            CBondUtil::GetCFETSQuoteById(key, btPriceFilter);
        *((double*)field) =
            (bi.IsCDCAuthValid())
                ? ToDashFloat(GetEstPriceOfr(pCfetsQuote, &bi, i, true))
                : MIN_UNAUTH_VALUE;
        break;
      }
      case kCFETS_Bid_CsiVal:  // CFETS bid-中证估值
      {
        CFETSQUOTE* pCfetsQuote =
            CBondUtil::GetCFETSQuoteById(key, btPriceFilter);
        *((double*)field) = m_csiauth
                                ? ToDashFloat(GetBidCsiPrice(pCfetsQuote, &bi))
                                : MIN_UNAUTH_VALUE;
        break;
      }
      case kCFETS_CsiVal_Ofr:  // CFETS 中证估值 - ofr
      {
        CFETSQUOTE* pCfetsQuote =
            CBondUtil::GetCFETSQuoteById(key, btPriceFilter);
        *((double*)field) = m_csiauth
                                ? ToDashFloat(GetCsiPriceOfr(pCfetsQuote, &bi))
                                : MIN_UNAUTH_VALUE;
        break;
      }
      case kCFETS_Update_Time:  // CFETS更新时间 kSortTypeDouble
      {
        CFETSQUOTE* pCfetsQuote =
            CBondUtil::GetCFETSQuoteById(key, btPriceFilter);
        *((double*)field) = (double)(pCfetsQuote->m_time);
        break;
      }
      case kCFETS_Deal_Price:  // CFETS 最新价
      {
        xQBCFETSDealAllUnit* unit = CBondUtil::GetCFETSDealById(key);
        *((double*)field) = atof(unit->m_price);
        break;
      }
      case kCFETS_Deal_Increase:  // CFETS 涨跌
      {
        xQBCFETSDealAllUnit* unit = CBondUtil::GetCFETSDealById(key);
        if (IsEmpty(unit->m_increase))
          *((double*)field) = MIN_UNAUTH_VALUE;
        else
          *((double*)field) = atof(unit->m_increase);
        break;
      }
      case kCFETS_Deal_WeightedMean:  // CFETS 加权平均
      {
        xQBCFETSDealAllUnit* unit = CBondUtil::GetCFETSDealById(key);
        *((double*)field) = atof(unit->m_weightedmean);
        break;
      }
      case kCFETS_Deal_Open:  // CFETS 开盘
      {
        xQBCFETSDealAllUnit* unit = CBondUtil::GetCFETSDealById(key);
        *((double*)field) = atof(unit->m_open);
        break;
      }
      case kCFETS_Deal_High:  // CFETS 最高
      {
        xQBCFETSDealAllUnit* unit = CBondUtil::GetCFETSDealById(key);
        *((double*)field) = atof(unit->m_high);
        break;
      }
      case kCFETS_Deal_Low:  // CFETS 最低
      {
        xQBCFETSDealAllUnit* unit = CBondUtil::GetCFETSDealById(key);
        *((double*)field) = atof(unit->m_low);
        break;
      }
      case kCFETS_Deal_PreClose:  // CFETS 昨收
      {
        xQBCFETSDealAllUnit* unit = CBondUtil::GetCFETSDealById(key);
        *((double*)field) = atof(unit->m_preclose);
        break;
      }
      case kCFETS_Deal_Vol:  // CFETS 成交量
      {
        xQBCFETSDealAllUnit* unit = CBondUtil::GetCFETSDealById(key);
        *((double*)field) = atof(unit->m_volume);
        break;
      }
      case kCFETS_Deal_CDC:  // CFETS 成交-中债
      {
        bool bIsCDCAuthValid = (bi.IsCDCAuthValid());
        if (!bIsCDCAuthValid) {
          *((double*)field) = MIN_UNAUTH_VALUE;
          break;
        }
        xQBCFETSDealAllUnit* unit = CBondUtil::GetCFETSDealById(key);
        int nOptType = CBondCDCPriceInfo::est_type_invalid;
        *((double*)field) =
            CBondCDCPriceInfo::instance().GetYesterdayCDCPriceGap(
                bIsCDCAuthValid, i, CBondCDCPriceInfo::price_type_yield, true,
                unit->m_price, INVALID_CDC_VALUE, 1);
        break;
      }
      case kCFETS_Deal_CSI:  // CFETS 成交-中证
      {
        if (!m_csiauth) {
          *((double*)field) = MIN_UNAUTH_VALUE;
          break;
        }
        xQBCFETSDealAllUnit* unit = CBondUtil::GetCFETSDealById(key);
        if (IsEmpty(unit->m_price)) {
          *((double*)field) = MIN_UNAUTH_VALUE;
          break;
        }

        double dValue = atof(unit->m_price);

        xCSIUint_c xUnit;
        if (!CBondCSInfo::instance().GetCsiUnit(bi.GetCombBondKey(), xUnit)) {
          *((double*)field) = MIN_UNAUTH_VALUE;
          break;
        }

        if (!xUnit.IsHaveYieldToExercise() && !xUnit.IsHaveYieldToMarturity()) {
          *((double*)field) = MIN_UNAUTH_VALUE;
          break;
        }

        double dExercise = xUnit.IsHaveExercise() ? xUnit.m_dYieldToExercise
                                                  : _INVALID_CSI_VALUE;
        double dMaturity = xUnit.IsHaveMarturity() ? xUnit.m_dYieldToMaturity
                                                   : _INVALID_CSI_VALUE;

        double dRet = _INVALID_CSI_VALUE;
        if (dExercise > _INVALID_CSI_VALUE && dMaturity > _INVALID_CSI_VALUE) {
          dExercise = dValue - dExercise;
          dMaturity = dValue - dMaturity;
          dRet = abs(dExercise) < abs(dMaturity) ? dExercise : dMaturity;
        } else if (dExercise > _INVALID_CSI_VALUE) {
          dRet = dValue - dExercise;
        } else if (dMaturity > _INVALID_CSI_VALUE) {
          dRet = dValue - dMaturity;
        }

        *((double*)field) = dRet;

        break;
      }
      case kCFETS_Deal_Time:  // CFETS 更新时间
      {
        xQBCFETSDealAllUnit* unit = CBondUtil::GetCFETSDealById(key);
        *((double*)field) = unit->m_time;
        break;
      }
      case kABSBondBaseType:  // ABS基础资产
      {
        const CABSBondInfo* absinfo =
            CBondContainer::instance().GetABSBondInfo(key.m_nIndex);
        if (absinfo) StringCopy(field, capcity, absinfo->GetBaseTypeString());
        break;
      }
      case kABSBondSeries:  // ABS系列
      {
        const CABSBondInfo* absinfo =
            CBondContainer::instance().GetABSBondInfo(key.m_nIndex);
        if (absinfo) StringCopy(field, capcity, absinfo->GetSeriesName());
        break;
      }
      case kABSBondFinancier:  // ABS实际融资人
      {
        const CABSBondInfo* absinfo =
            CBondContainer::instance().GetABSBondInfo(key.m_nIndex);
        if (absinfo) StringCopy(field, capcity, absinfo->GetAcutulFinancier());
        break;
      }
      case kABSBondIssuer:  // ABS发行人
      {
        const CABSBondInfo* absinfo =
            CBondContainer::instance().GetABSBondInfo(key.m_nIndex);
        if (absinfo) StringCopy(field, capcity, absinfo->GetIssuerCode());
        break;
      }
      case kBondMainUnderwriter:  // 主承机构
        StringCopy(field, capcity, bi.GetMainUnderwriters());
        break;
      case VBondIssueType: {
        if (!bi.is_interest_bond() && strcmp(bi.GetAssetStatus(), "PRI") != 0 &&
            strcmp(bi.GetAssetStatus(), "PUB") != 0) {
          *((int*)field) = 0;  // 公募
        } else if (strcmp(bi.GetAssetStatus(), "PUB") == 0) {
          *((int*)field) = 2;  // 小公募
        } else if (strcmp(bi.GetAssetStatus(), "PRI") == 0) {
          *((int*)field) = 1;  // 私募
        } else {
          // 空
          if (!bAscend)
            *((int*)field) = -1;
          else
            *((int*)field) = INT_MAX;
        }
        break;
      }
      case VMunicipalBond: {
        if (strcmp(bi.GetBondSubType(), "LLB") == 0 &&
            strcmp(bi.GetEntCor(), "SMB") == 0) {
          *((int*)field) = 0;  // 一般债
        } else if (strcmp(bi.GetBondSubType(), "LLB") == 0 &&
                   strcmp(bi.GetEntCor(), "NMB") == 0) {
          *((int*)field) = 1;  // 专项债
        } else {
          // 空
          if (!bAscend)
            *((int*)field) = -1;
          else
            *((int*)field) = INT_MAX;
        }
        break;
      }
      case kABRecommendPrice: {
        if (strcmp(SSUserAccountManager::instance().GetPermission().GetValue(
                       USER_PERMISSION_WEB_ANALYSIS),
                   "1") == 0) {
          const char* strABPrice = CABBondPriceInfo::instance().GetPrice(i);
          *((double*)field) = strABPrice == NULL ? (bAscend ? MAX_VAL : -999)
                                                 : atof(strABPrice);
        } else {
          if (!bAscend)
            *((double*)field) = -999;
          else
            *((double*)field) = MAX_VAL;
        }
        break;
      }
      default:
        return false;
    }
    return true;
  }
};
}  // namespace
namespace {
#define GetDoubleFlag(d) (d) > 0.000001 ? 1 : ((d) < -0.000001 ? (-1) : 0)
#ifndef _MSC_VER
#define FORCEINLINE
#endif
FORCEINLINE int CompareDouble(double dValue1, double dValue2) {
  double delta = dValue1 - dValue2;
  return GetDoubleFlag(delta);
}

FORCEINLINE int StringComparator(const void* f1, const void* f2) {
  return strcmp((const char*)f1, (const char*)f2);
}
FORCEINLINE int DoubleComparator(const void* f1, const void* f2) {
  double delta = *((const double*)f1) - *((const double*)f2);
  return GetDoubleFlag(delta);
}
FORCEINLINE int TimeComparator(const void* f1, const void* f2) {
  time_t i1 = *((const time_t*)f1), i2 = *((const time_t*)f2);
  return i1 == i2 ? 0 : (i1 < i2 ? -1 : 1);
}
FORCEINLINE int IntComparator(const void* f1, const void* f2) {
  int i1 = *((const int*)f1), i2 = *((const int*)f2);
  return i1 == i2 ? 0 : (i1 < i2 ? -1 : 1);
}
FORCEINLINE int CharComparator(const void* f1, const void* f2) {
  char i1 = *((const char*)f1), i2 = *((const char*)f2);
  return i1 == i2 ? 0 : (i1 < i2 ? -1 : 1);
}
FORCEINLINE int BidLimitComparator(const void* f1, const void* f2) {
  double bot1 = *((const double*)f1), top1 = *((const double*)f1 + 1);
  double bot2 = *((const double*)f2), top2 = *((const double*)f2 + 1);
  if (bot1 == bot2) return CompareDouble(top1, top2);
  return CompareDouble(bot1, bot2);
}
FORCEINLINE int MaturityTermEndComparator(const void* f1, const void* f2) {
  int b1 = *((const int*)f1), b2 = *((const int*)f2);
  std::string iMaturityTerm_s = GetBond(b1).GetMaturityTerm();
  std::string jMaturityTerm_s = GetBond(b2).GetMaturityTerm();
  int iMaturityTerm = CSSVContainer::CalMaturityTerm(iMaturityTerm_s);
  int jMaturityTerm = CSSVContainer::CalMaturityTerm(jMaturityTerm_s);
  if (iMaturityTerm != jMaturityTerm)
    return iMaturityTerm - jMaturityTerm;
  else {
    int iComp = strcmp(GetBond(b1).GetTermToMaturity(),
                       GetBond(b2).GetTermToMaturity());
    if (0 == iComp)
      return CSSVContainer::CalMaturityType(iMaturityTerm_s) -
             CSSVContainer::CalMaturityType(jMaturityTerm_s);
    else
      return iComp;
  }
}
FORCEINLINE int TermToMaturityComparator(const void* f1, const void* f2) {
  int b1 = *((const int*)f1), b2 = *((const int*)f2);
  std::string iMaturityTerm_s = GetBond(b1).GetTermToMaturity();
  std::string jMaturityTerm_s = GetBond(b2).GetTermToMaturity();
  if (iMaturityTerm_s == jMaturityTerm_s) return 0;
  int iMaturityTerm = CSSVContainer::CalMaturityTerm(iMaturityTerm_s);
  int jMaturityTerm = CSSVContainer::CalMaturityTerm(jMaturityTerm_s);
  return iMaturityTerm - jMaturityTerm;
}
FORCEINLINE int IssuePeriodComparator(const void* f1, const void* f2) {
  const IssuePeriod& ip1 = *((const IssuePeriod*)f1);
  const IssuePeriod& ip2 = *((const IssuePeriod*)f2);
  if (ip1.nAscend == ip2.nAscend) {
    if (ip1.nAscend == 2)  // 都是募集时间，则按字符串排序
      return strcmp(GetBond(ip1.nBondIndex).GetIssuePeriod(),
                    GetBond(ip2.nBondIndex).GetIssuePeriod());
    return (ip1.nDate == ip2.nDate) ? 0 : ((ip1.nDate > ip2.nDate) ? 1 : -1);
  }
  return ip1.nAscend > ip2.nAscend ? 1 : -1;
}
}  // namespace
////////////////////////////////////////////////////////////////////////////////
/*
此对象可能会消耗
        债券个数*经纪商个数*(排序列字段总字节+sizeof(BrokerKeyInfo))
        债券个数*经纪商个数*(sizeof(INDEX))

        当有5w债券,5个经纪商,那么最大消耗内存大概是
                发行人机构全称	25w*(8+8+128)	= 34mb
                代码					25w*(8+8+12)	= 7mb
                简称					25w*(8+8+32)	= 12mb
*/
class CBondSortManager {
  struct INDEX {
    int index, offset;
    INDEX(int i, int o) : index(i), offset(o) {}
  };
  int m_comp_count;
  std::vector<SortInfo> m_sortinfos;
  char* m_buffer;               // 全排后的所有排序记录的内存
  int m_capcity;                // m_buffer 的实际内存大小
  FiledInfoMap m_fields;        // bond的每列信息,创建后基本不变
  ComparatorMap m_comparators;  // 持有的排序类型的比较函数的表
  std::vector<INDEX>
      m_indexes;  // 排序前,为0-总个数分别指向m_buffer中的排序记录的索引
  BondReader*
      m_bond_reader;  // 如何根据bondindex和brokerid,来获取制定列的排序数据
  int m_reference;                       // 引用计数
  static CBondSortManager* m_singleton;  //
 protected:
  bool AddReference(int i) {
    m_reference += i;
    return m_reference > 0;
  }

 public:
  static CBondSortManager* Acquire() {
    if (m_singleton == 0) {
      m_singleton = new CBondSortManager();
    }
    m_singleton->AddReference(1);
    return m_singleton;
  }
  static void Release(CBondSortManager* sortManager) {
    (sortManager && sortManager == m_singleton);
    if (!sortManager->AddReference(-1)) {
      delete sortManager;
      m_singleton = 0;
    }
  }
  CBondSortManager();
  ~CBondSortManager();
  void Sort(vector<BrokerKeyInfo>& keys, const std::vector<SortInfo>& sortinfos,
            int ncorpid, int recordSize);
  void Sort(vector<BrokerKeyInfo>& keys, const std::vector<SortInfo>& sortinfos,
            BYTE btSettlement, int ncorpid, int recordSize);
  void Sort(vector<BrokerKeyInfo>& keys, const std::vector<SortInfo>& sortinfos,
            std::string& contributorId, BYTE btPriceFilter, int ncorpid,
            int recordSize);
  bool GetRecordField(const BrokerKey& key, int col, char* field, int capcity,
                      bool batchMode = true) {
    return m_bond_reader->GetRecordField(key, col, field, capcity, batchMode);
  }
  bool GetFieldInfo(int column, FieldInfo& fi) {
    FiledInfoMap::iterator it = m_fields.find(column);
    if (it != m_fields.end()) {
      fi = it->second;
      return true;
    }
    return false;
  }

  FieldComparator GetComparator(int type);

 protected:
  void LoadSortData(vector<BrokerKeyInfo>& keys,
                    std::vector<SortInfo>& sortinfos, int recordSize);
  void LoadSortData(vector<BrokerKeyInfo>& keys,
                    std::vector<SortInfo>& sortinfos, int recordSize,
                    BYTE btSettlement);
  void LoadSortData(vector<BrokerKeyInfo>& keys,
                    std::vector<SortInfo>& sortinfos, int recordSize,
                    std::string& contributorId, BYTE btPriceFilter);
  char* PrepareBuffer(int nCount, int nRecordSize);
  void SetComparator(int type, FieldComparator comparator);
  void SetFieldImpl(int column, const char* name, int sortType, int bytes);
  inline int CompareRecord(const INDEX& k1, const INDEX& k2) {
    int cmp = 0, ncount = m_sortinfos.size();
    m_comp_count++;
    for (int i = 0; i < ncount; i++) {
      SortInfo& si = m_sortinfos[i];
      cmp = si.comparator(m_buffer + k1.offset + si.offset,
                          m_buffer + k2.offset + si.offset);
      cmp = si.ascend ? cmp : -cmp;
      if (cmp != 0) return cmp;
    }
    return cmp;
  }
  void CheckSort() {
    int less = 0, large = 0;
    for (int i = 1; i < (int)m_indexes.size(); i++) {
      int cmp = CompareRecord(m_indexes[i - 1], m_indexes[i]);
      if (cmp == 0)
        continue;
      else if (cmp < 0)
        less++;
      else if (cmp > 0)
        large++;
    }
    if (less + 1 < (int)m_indexes.size() && large + 1 < (int)m_indexes.size()) {
      log_error("sort check failed,less:%d large:%d", less, large);
    } else {
      log_error("sort check success,%s", less > 0 ? "asccend" : "desccend");
    }
  }
};
CBondSortManager* CBondSortManager::m_singleton = 0;
CBondSortManager::CBondSortManager()
    : m_comp_count(0), m_capcity(0), m_buffer(0), m_reference(0) {
  m_bond_reader = new BondReader();

  SetComparator(kSortTypeString, StringComparator);
  SetComparator(kSortTypeDouble, DoubleComparator);
  SetComparator(kSortTypeInt, IntComparator);
  SetComparator(kSortTypeChar, CharComparator);
  SetComparator(kSortTypeBidLimit, BidLimitComparator);
  SetComparator(kSortTypeMaturityTermEnd, MaturityTermEndComparator);
  SetComparator(kSortTypeTermToMaturity, TermToMaturityComparator);
  SetComparator(kSortTypeIssuePeriod, IssuePeriodComparator);

#define SetField(COL, TYPE, SIZE) SetFieldImpl(COL, #COL, TYPE, SIZE);
  SetField(VBOND_CODE, kSortTypeString, sizeof(tBondCode));
  SetField(VSHORT_NAME, kSortTypeString,
           32);  // max(m_sShortName,m_sShortNameEn));
  SetField(VSHORT_NAME_EN, kSortTypeString,
           128);  // max(m_sShortName,m_sShortNameEn));
  SetField(VEXPIRY_DATE, kSortTypeDouble, sizeof(double));
  SetField(VBUYVOL, kSortTypeDouble, sizeof(double));
  SetField(VBUYVOL_SETTLEMENT, kSortTypeDouble, sizeof(double));
  SetField(VBUYPRICE, kSortTypeDouble, sizeof(double));
  SetField(VBUYPRICE_SETTLEMENT, kSortTypeDouble, sizeof(double));
  SetField(VBUYNETPRICE, kSortTypeDouble, sizeof(double));
  SetField(VBUYNETPRICE_SETTLEMENT, kSortTypeDouble, sizeof(double));
  SetField(VBUYFULLPRICE_SETTLEMENT, kSortTypeDouble, sizeof(double));
  SetField(VSELLVOL, kSortTypeDouble, sizeof(double));
  SetField(VSELLVOL_SETTLEMENT, kSortTypeDouble, sizeof(double));
  SetField(VSELLPRICE, kSortTypeDouble, sizeof(double));
  SetField(VSELLPRICE_SETTLEMENT, kSortTypeDouble, sizeof(double));
  SetField(VSELLNETPRICE, kSortTypeDouble, sizeof(double));
  SetField(VSELLNETPRICE_SETTLEMENT, kSortTypeDouble, sizeof(double));
  SetField(VSELLFULLPRICE_SETTLEMENT, kSortTypeDouble, sizeof(double));
  SetField(VMODIFY_TIME, kSortTypeDouble, sizeof(double));
  SetField(VMODIFY_TIME_SETTLEMENT, kSortTypeDouble, sizeof(double));
  SetField(VRATING, kSortTypeInt, sizeof(int));
  SetField(VESTBPRICEPRE, kSortTypeDouble, sizeof(double));
  SetField(VESTBPRICETODAY, kSortTypeDouble, sizeof(double));
  SetField(VESTBCLEPRICE, kSortTypeDouble, sizeof(double));
  // case VBOND_TYPE:/*sort_bond_type*/break;
  // case VBUYCLEPRICE:/*sort_bcle_price*/break;
  // case VSELLCLEPRICE:/*sort_scle_price*/break;
  // case VMATURITY_DATE:/*sort_maturity_date*/break;
  // case VCROSSMARKET:/*sort_cross_market*/break;
  SetField(VBROKERKEY, kSortTypeInt, sizeof(int));
  SetField(VISSUERRATING, kSortTypeInt, sizeof(int));
  SetField(VBONDRATING, kSortTypeInt, sizeof(int));

  SetField(VCDCRATING, kSortTypeInt, sizeof(int));
  SetField(VCSIRATING, kSortTypeInt, sizeof(int));
  SetField(VCBRRATING, kSortTypeInt, sizeof(int));

  SetField(INDICATIVE_PRICE, kSortTypeDouble, sizeof(double));
  SetField(VTKNPRICE, kSortTypeDouble, sizeof(double));
  SetField(BSVTKPRICE, kSortTypeDouble, sizeof(double));
  SetField(PLANNED_ISSURE_AMOUNT, kSortTypeDouble, sizeof(double));
  SetField(BID_LIMIT, kSortTypeBidLimit, sizeof(double) * 2);
  SetField(AUCTION_LIMIT, kSortTypeBidLimit, sizeof(double) * 2);
  SetField(ISSUE_START_DATE, kSortTypeInt, sizeof(int));
  SetField(PAYMENT_DATE, kSortTypeInt, sizeof(int));
  SetField(LISTED_DATE, kSortTypeInt, sizeof(int));
  SetField(INSTITUTION_TYPE, kSortTypeInt, sizeof(int));
  SetField(ANNOUNCE_DATE, kSortTypeInt, sizeof(int));
  SetField(COUPON_RATE, kSortTypeDouble, sizeof(double));
  SetField(MATURITY_TERM_END, kSortTypeMaturityTermEnd, sizeof(int));
  SetField(TERM_TO_MATURITY, kSortTypeTermToMaturity, sizeof(int));
  SetField(AREA, kSortTypeString,
           RTL_FIELD_SIZE(QBPROVINCEINFO, Area_Name));  // CBondInfo::GetArea()
  SetField(
      SECTOR, kSortTypeString,
      RTL_FIELD_SIZE(QBSWSECTORINFO, SW_Name));  // CBondInfo::GetSwSector()
  SetField(INTEREST_START_DATE, kSortTypeString,
           sizeof(tDate8));  // CBondInfo::m_sInterestStartDate
  SetField(kInstitutionName, kSortTypeString,
           RTL_FIELD_SIZE(QBISSUERINFO,
                          Short_Name_C));  // CBondInfo::GetInstitutionShortName
  SetField(kIssueEndTime, kSortTypeString,
           sizeof(tDate8) * 2);  // GetIssueStartDate+GetIssueEndTime
  SetField(kActualIssureAmount, kSortTypeDouble, sizeof(double));
  SetField(kIssuerAmount, kSortTypeDouble, sizeof(double));
  SetField(kCouponType, kSortTypeString,
           RTL_FIELD_SIZE(
               BondDict,
               selective_content));  // GetCouponTypeName-------------------very
                                     // large 512

  SetField(
      kRateType, kSortTypeString,
      RTL_FIELD_SIZE(
          BondDict,
          selective_content));  // GetCouponTypeName-------------------very l

  SetField(kDuration, kSortTypeDouble, sizeof(double));
  SetField(kBid_EstPrice, kSortTypeDouble, sizeof(double));
  SetField(kBid_EstPrice_Settlement, kSortTypeDouble, sizeof(double));
  SetField(kEstPrice_Ofr, kSortTypeDouble, sizeof(double));
  SetField(kEstPrice_Ofr_Settlement, kSortTypeDouble, sizeof(double));
  SetField(kOutlook, kSortTypeInt, sizeof(int));  // CBondInfo::m_sOutlook;
  SetField(kIssuerPeriod, kSortTypeIssuePeriod,
           sizeof(IssuePeriod));  // compare_IssuePeriod
  SetField(kInstitutionFullName, kSortTypeString,
           max(RTL_FIELD_SIZE(QBISSUERINFO, Short_Name_C),
               RTL_FIELD_SIZE(QBISSUERINFO,
                              Full_Name_E)));  // GetInstitutionFullName
  SetField(ISSUE_DATE_IsuPeriod, kSortTypeInt, sizeof(int));
  SetField(PAYMENT_DATE_IsuPeriod, kSortTypeInt, sizeof(int));
  SetField(LISTED_DATE_IsuPeriod, kSortTypeInt, sizeof(int));
  SetField(ANNOUNCE_DATE_IsuPeriod, kSortTypeInt, sizeof(int));
  SetField(INTEREST_DATE_IsuPeriod, kSortTypeString,
           sizeof(tDate8));  // m_sInterestStartDate
  SetField(kIssueRate, kSortTypeDouble, sizeof(double));
  SetField(kConvRate, kSortTypeDouble, sizeof(double));
  SetField(kTknPrice, kSortTypeDouble, sizeof(double));
  SetField(kCleanPriceDiv, kSortTypeDouble, sizeof(double));
  SetField(kTknYield, kSortTypeDouble, sizeof(double));
  SetField(kYieldDiv, kSortTypeDouble, sizeof(double));
  SetField(kCouponRate, kSortTypeDouble, sizeof(double));
  SetField(kCsiVal, kSortTypeDouble, sizeof(double));
  SetField(kCsiCleanPrice, kSortTypeDouble, sizeof(double));
  SetField(kCdcCleanPrice, kSortTypeDouble, sizeof(double));
  SetField(kOptionType, kSortTypeString, 8);  // m_sOptionType
  SetField(kOptionDate, kSortTypeDouble, sizeof(double));
  SetField(kCsi_Cdc, kSortTypeDouble, sizeof(double));
  SetField(kCrossMarket, kSortTypeChar, sizeof(char));
  SetField(kIndustry, kSortTypeString, RTL_FIELD_SIZE(QBSWSECTORINFO, SW_Name));
  SetField(kIndustryEn, kSortTypeString,
           RTL_FIELD_SIZE(QBSWSECTORINFO, SW_English_Name));
  SetField(kRatingAgency, kSortTypeString,
           RTL_FIELD_SIZE(QBISSUERINFO, Short_Name_C));

  SetField(VBondType, kSortTypeInt, sizeof(int));
  SetField(VBondIssuer, kSortTypeString, 10);
  SetField(kBondGuarantor, kSortTypeString, 64);
  SetField(kBondGuarantorEn, kSortTypeString, 64);
  SetField(kBondLiquidity, kSortTypeDouble, sizeof(double));
  SetField(kIssuerLiquidity, kSortTypeDouble, sizeof(double));
  SetField(kOutstandingAmount, kSortTypeDouble, sizeof(double));

  SetField(kBid_CsiVal, kSortTypeDouble, sizeof(double));
  SetField(kBid_CsiVal_Settlement, kSortTypeDouble, sizeof(double));
  SetField(kCsiVal_Ofr, kSortTypeDouble, sizeof(double));
  SetField(kCsiVal_Ofr_Settlement, kSortTypeDouble, sizeof(double));
  SetField(kMaturityDate, kSortTypeString, sizeof(tDate8));  // m_sMaturityDate
  SetField(kMaturityDate_IsuPeriod, kSortTypeString,
           sizeof(tDate8));  // m_sMaturityDate
  SetField(kDeal_Cdc, kSortTypeDouble, sizeof(double));
  SetField(kDeal_Csi, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Buyer, kSortTypeString, 80);  // 结构内为string, 有截断风险
  SetField(kCFETS_BidFull, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_BidVol, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_BidClean, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Bid, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Ofr, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_OfrClean, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_OfrVol, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_OfrFull, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Seller, kSortTypeString, 80);  // 结构内为string, 有截断风险
  SetField(kCFETS_Bid_CdcVal, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_CdcVal_Ofr, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Bid_CsiVal, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_CsiVal_Ofr, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Update_Time, kSortTypeDouble, sizeof(double));
  SetField(kTknCleanCleanPrice, kSortTypeDouble, sizeof(double));

  SetField(kCFETS_Deal_Price, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Deal_Increase, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Deal_WeightedMean, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Deal_Open, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Deal_High, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Deal_Low, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Deal_PreClose, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Deal_Vol, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Deal_CDC, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Deal_CSI, kSortTypeDouble, sizeof(double));
  SetField(kCFETS_Deal_Time, kSortTypeDouble, sizeof(double));

  SetField(fisse_deal_netprice, kSortTypeDouble, sizeof(double));
  SetField(fisse_deal_fullprice, kSortTypeDouble, sizeof(double));
  SetField(fisse_deal_yield, kSortTypeDouble, sizeof(double));
  SetField(fisse_deal_volumn, kSortTypeDouble, sizeof(double));
  SetField(fisse_deal_amount, kSortTypeDouble, sizeof(double));

  SetField(kABSBondBaseType, kSortTypeString, 32);
  SetField(kABSBondSeries, kSortTypeString, 32);
  SetField(kABSBondIssuer, kSortTypeString, 10);
  SetField(kBondMainUnderwriter, kSortTypeString, 64);
}
CBondSortManager::~CBondSortManager() {
  if (m_bond_reader) delete m_bond_reader;
  if (m_buffer) {
    delete[] m_buffer;
    m_buffer = 0;
  }
}
void CBondSortManager::SetComparator(int type, FieldComparator comparator) {
  m_comparators[type] = comparator;
}
FieldComparator CBondSortManager::GetComparator(int type) {
  return m_comparators[type];
}
void CBondSortManager::SetFieldImpl(int column, const char* name, int sortType,
                                    int bytes) {
  // 一次性设置
  FieldInfo fi;
  fi.column_id = column;
  fi.field_bytes = (bytes % 4 != 0) ? ((bytes / 4 + 1) * 4) : bytes;
  fi.sort_type = sortType;
  fi.column_name = name;
  m_fields[column] = fi;
}

char* CBondSortManager::PrepareBuffer(int nCount, int nRecordSize) {
  SASSERT(nRecordSize > 0 && nRecordSize % 4 == 0);
  int total_size = nCount * nRecordSize;
  if (m_buffer == 0 || m_capcity < total_size) {
    total_size = total_size < 4096 ? 4096 : total_size;
    if (m_buffer) delete[] m_buffer;
    m_buffer = new char[total_size];
    m_capcity = total_size;
  }
  memset(m_buffer, 0, m_capcity);
  return m_buffer;
}

void CBondSortManager::LoadSortData(vector<BrokerKeyInfo>& keys,
                                    std::vector<SortInfo>& sortinfos,
                                    int recordSize) {
  int nCount = keys.size();
  m_indexes.clear();
  m_indexes.reserve(nCount);
  char* buffer = PrepareBuffer(nCount, recordSize);
  char* end = buffer + m_capcity;
  char* record = buffer;
  BrokerKey key;
  for (int i = 0; i < nCount; i++) {
    const BrokerKeyInfo& bki = keys[i];
    *((BrokerKeyInfo*)record) = bki;
    bki.GetBrokerKey(key);
    for (int j = 0; j < (int)sortinfos.size(); j++) {
      SortInfo& si = sortinfos[j];
      m_bond_reader->GetRecordField(key, si.column_id, record + si.offset,
                                    si.field_bytes, 0);
    }
    record += recordSize;
    SASSERT(record <= end);
    m_indexes.push_back(INDEX(i, i * recordSize));
  }
}

void CBondSortManager::LoadSortData(vector<BrokerKeyInfo>& keys,
                                    std::vector<SortInfo>& sortinfos,
                                    int recordSize, BYTE btSettlement) {
  int nCount = keys.size();
  m_indexes.clear();
  m_indexes.reserve(nCount);
  char* buffer = PrepareBuffer(nCount, recordSize);
  char* end = buffer + m_capcity;
  char* record = buffer;
  BrokerKey key;
  for (int i = 0; i < nCount; i++) {
    const BrokerKeyInfo& bki = keys[i];
    *((BrokerKeyInfo*)record) = bki;
    bki.GetBrokerKey(key);
    for (int j = 0; j < (int)sortinfos.size(); j++) {
      SortInfo& si = sortinfos[j];
      m_bond_reader->GetRecordField(key, si.column_id, record + si.offset,
                                    si.field_bytes, btSettlement);
    }
    record += recordSize;
    SASSERT(record <= end);
    m_indexes.push_back(INDEX(i, i * recordSize));
  }
}

void CBondSortManager::LoadSortData(vector<BrokerKeyInfo>& keys,
                                    std::vector<SortInfo>& sortinfos,
                                    int recordSize, std::string& contributorId,
                                    BYTE btPriceFilter) {
  int nCount = keys.size();
  m_indexes.clear();
  m_indexes.reserve(nCount);
  char* buffer = PrepareBuffer(nCount, recordSize);
  char* end = buffer + m_capcity;
  char* record = buffer;
  BrokerKey key;
  for (int i = 0; i < nCount; i++) {
    const BrokerKeyInfo& bki = keys[i];
    *((BrokerKeyInfo*)record) = bki;
    key.m_nIndex = bki.m_nIndex;
    key.SetBrokerId(contributorId.c_str());
    for (int j = 0; j < (int)sortinfos.size(); j++) {
      SortInfo& si = sortinfos[j];
      m_bond_reader->GetRecordField(key, si.column_id, record + si.offset,
                                    si.field_bytes, btPriceFilter & 0xF0, true,
                                    si.ascend);
    }
    record += recordSize;
    SASSERT(record <= end);
    m_indexes.push_back(INDEX(i, i * recordSize));
  }
}

void CBondSortManager::Sort(vector<BrokerKeyInfo>& keys,
                            const std::vector<SortInfo>& sortinfos, int ncorpid,
                            int recordSize) {
  class Comparator {
    CBondSortManager& m_sort_manager;

   public:
    Comparator(CBondSortManager& sb) : m_sort_manager(sb) {}
    bool operator()(const INDEX& i1, const INDEX& i2) {
      return m_sort_manager.CompareRecord(i1, i2) < 0;
    }
  };
  class OneColumnAscendComp {  // 绝大多数都是单列排序,优化此类场景
    char* m_buffer;            //
    FieldComparator m_comp;  // 该字段的比较器,通用比较器只比较递增
   public:
    OneColumnAscendComp(const SortInfo& sort, char* buf)
        : m_comp(sort.comparator), m_buffer(buf + sort.offset) {}
    inline bool operator()(const INDEX& k1, const INDEX& k2) {
      return m_comp(m_buffer + k1.offset, m_buffer + k2.offset) < 0;
    }
  };
  class OneColumnDescentComp {  // 绝大多数都是单列排序,优化此类场景
    char* m_buffer;             //
    FieldComparator m_comp;  // 该字段的比较器,通用比较器只比较递增
   public:
    OneColumnDescentComp(const SortInfo& sort, char* buf)
        : m_comp(sort.comparator), m_buffer(buf + sort.offset) {}
    inline bool operator()(const INDEX& k1, const INDEX& k2) {
      return m_comp(m_buffer + k1.offset, m_buffer + k2.offset) > 0;
    }
  };
  if (keys.size() <= 1 || sortinfos.size() < 0) return;
  m_sortinfos = sortinfos;
  m_bond_reader->PreGetRecordField(sortinfos, ncorpid);
  const FieldInfo& fi = m_fields[m_sortinfos[0].column_id];

  {
    STACK_METRICS("LoadSortData %d column:%d-%s bytes:%d sort-type:%d",
                  keys.size(), fi.column_id, fi.column_name, fi.field_bytes,
                  fi.sort_type);
    LoadSortData(keys, m_sortinfos, recordSize);
  }

  {
    m_comp_count = 0;
    STACK_METRICS("std::sort, count:%d capcity:%d,column:%d-%s bytes:%d",
                  keys.size(), m_capcity, fi.column_id, fi.column_name,
                  fi.field_bytes);
    if (m_sortinfos.size() == 1) {
      const SortInfo& si = m_sortinfos[0];
      if (si.ascend)
        std::sort(m_indexes.begin(), m_indexes.end(),
                  OneColumnAscendComp(si, m_buffer));
      else
        std::sort(m_indexes.begin(), m_indexes.end(),
                  OneColumnDescentComp(si, m_buffer));
    } else
      std::sort(m_indexes.begin(), m_indexes.end(), Comparator(*this));
  }

  char* record = m_buffer;
  {
    STACK_METRICS("set std::vector<BrokerKey>");
    SASSERT(m_indexes.size() == keys.size());
    for (int i = 0; i < (int)keys.size(); i++) {
      BrokerKeyInfo& bki = *((BrokerKeyInfo*)(record + m_indexes[i].offset));
      keys[i] = bki;
    }
  }
}

void CBondSortManager::Sort(vector<BrokerKeyInfo>& keys,
                            const std::vector<SortInfo>& sortinfos,
                            BYTE btSettlement, int ncorpid, int recordSize) {
  class Comparator {
    CBondSortManager& m_sort_manager;

   public:
    Comparator(CBondSortManager& sb) : m_sort_manager(sb) {}
    bool operator()(const INDEX& i1, const INDEX& i2) {
      return m_sort_manager.CompareRecord(i1, i2) < 0;
    }
  };
  class OneColumnAscendComp {  // 绝大多数都是单列排序,优化此类场景
    char* m_buffer;            //
    FieldComparator m_comp;  // 该字段的比较器,通用比较器只比较递增
   public:
    OneColumnAscendComp(const SortInfo& sort, char* buf)
        : m_comp(sort.comparator), m_buffer(buf + sort.offset) {}
    inline bool operator()(const INDEX& k1, const INDEX& k2) {
      return m_comp(m_buffer + k1.offset, m_buffer + k2.offset) < 0;
    }
  };
  class OneColumnDescentComp {  // 绝大多数都是单列排序,优化此类场景
    char* m_buffer;             //
    FieldComparator m_comp;  // 该字段的比较器,通用比较器只比较递增
   public:
    OneColumnDescentComp(const SortInfo& sort, char* buf)
        : m_comp(sort.comparator), m_buffer(buf + sort.offset) {}
    inline bool operator()(const INDEX& k1, const INDEX& k2) {
      return m_comp(m_buffer + k1.offset, m_buffer + k2.offset) > 0;
    }
  };
  if (keys.size() <= 1 || sortinfos.size() < 0) return;
  m_sortinfos = sortinfos;
  m_bond_reader->PreGetRecordField(sortinfos, ncorpid);
  const FieldInfo& fi = m_fields[m_sortinfos[0].column_id];

  {
    STACK_METRICS("LoadSortData %d column:%d-%s bytes:%d sort-type:%d",
                  keys.size(), fi.column_id, fi.column_name, fi.field_bytes,
                  fi.sort_type);
    LoadSortData(keys, m_sortinfos, recordSize, btSettlement);
  }

  {
    m_comp_count = 0;
    STACK_METRICS("std::sort, count:%d capcity:%d,column:%d-%s bytes:%d",
                  keys.size(), m_capcity, fi.column_id, fi.column_name,
                  fi.field_bytes);
    if (m_sortinfos.size() == 1) {
      const SortInfo& si = m_sortinfos[0];
      if (si.ascend)
        std::sort(m_indexes.begin(), m_indexes.end(),
                  OneColumnAscendComp(si, m_buffer));
      else
        std::sort(m_indexes.begin(), m_indexes.end(),
                  OneColumnDescentComp(si, m_buffer));
    } else
      std::sort(m_indexes.begin(), m_indexes.end(), Comparator(*this));
  }

  char* record = m_buffer;
  {
    STACK_METRICS("set std::vector<BrokerKey>");
    SASSERT(m_indexes.size() == keys.size());
    for (int i = 0; i < (int)keys.size(); i++) {
      BrokerKeyInfo& bki = *((BrokerKeyInfo*)(record + m_indexes[i].offset));
      keys[i] = bki;
    }
  }
}

void CBondSortManager::Sort(vector<BrokerKeyInfo>& keys,
                            const std::vector<SortInfo>& sortinfos,
                            std::string& contributorId, BYTE btPriceFilter,
                            int ncorpid, int recordSize) {
  class Comparator {
    CBondSortManager& m_sort_manager;

   public:
    Comparator(CBondSortManager& sb) : m_sort_manager(sb) {}
    bool operator()(const INDEX& i1, const INDEX& i2) {
      return m_sort_manager.CompareRecord(i1, i2) < 0;
    }
  };
  class OneColumnAscendComp {  // 绝大多数都是单列排序,优化此类场景
    char* m_buffer;            //
    FieldComparator m_comp;  // 该字段的比较器,通用比较器只比较递增
   public:
    OneColumnAscendComp(const SortInfo& sort, char* buf)
        : m_comp(sort.comparator), m_buffer(buf + sort.offset) {}
    inline bool operator()(const INDEX& k1, const INDEX& k2) {
      return m_comp(m_buffer + k1.offset, m_buffer + k2.offset) < 0;
    }
  };
  class OneColumnDescentComp {  // 绝大多数都是单列排序,优化此类场景
    char* m_buffer;             //
    FieldComparator m_comp;  // 该字段的比较器,通用比较器只比较递增
   public:
    OneColumnDescentComp(const SortInfo& sort, char* buf)
        : m_comp(sort.comparator), m_buffer(buf + sort.offset) {}
    inline bool operator()(const INDEX& k1, const INDEX& k2) {
      return m_comp(m_buffer + k1.offset, m_buffer + k2.offset) > 0;
    }
  };
  if (keys.size() <= 1 || sortinfos.size() < 0) return;
  m_sortinfos = sortinfos;
  m_bond_reader->PreGetRecordField(sortinfos, ncorpid);
  const FieldInfo& fi = m_fields[m_sortinfos[0].column_id];

  {
    STACK_METRICS("LoadSortData %d column:%d-%s bytes:%d sort-type:%d",
                  keys.size(), fi.column_id, fi.column_name, fi.field_bytes,
                  fi.sort_type);
    LoadSortData(keys, m_sortinfos, recordSize, contributorId, btPriceFilter);
  }

  {
    m_comp_count = 0;
    STACK_METRICS("std::sort, count:%d capcity:%d,column:%d-%s bytes:%d",
                  keys.size(), m_capcity, fi.column_id, fi.column_name,
                  fi.field_bytes);
    if (m_sortinfos.size() == 1) {
      const SortInfo& si = m_sortinfos[0];
      if (si.ascend)
        std::sort(m_indexes.begin(), m_indexes.end(),
                  OneColumnAscendComp(si, m_buffer));
      else
        std::sort(m_indexes.begin(), m_indexes.end(),
                  OneColumnDescentComp(si, m_buffer));
    } else
      std::sort(m_indexes.begin(), m_indexes.end(), Comparator(*this));

    if (CBondSorter::GetCheckBool("CheckSort")) {
      CheckSort();
    }
    {
      STACK_METRICS("m_comp_count=%d  size:%d", m_comp_count, m_indexes.size());
    }
  }

  char* record = m_buffer;
  {
    STACK_METRICS("set std::vector<BrokerKey>");
    SASSERT(m_indexes.size() == keys.size());
    for (int i = 0; i < (int)keys.size(); i++) {
      BrokerKeyInfo& bki = *((BrokerKeyInfo*)(record + m_indexes[i].offset));
      keys[i] = bki;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
CBondSorter::CBondSorter()
    : m_record_head_size(sizeof(BrokerKeyInfo)),
      m_record_size(0),
      m_buffer(0),
      m_capcity(0) {
  m_record_head_size = sizeof(BrokerKeyInfo);
  m_sort_manager = new CBondSortManager();
  // m_sort_manager = CBondSortManager::Acquire();
  SASSERT(m_sort_manager != 0);
}

CBondSorter::~CBondSorter() {
  delete m_sort_manager;
  // CBondSortManager::Release(m_sort_manager);
  if (m_buffer) {
    delete[] m_buffer;
    m_buffer = 0;
  }
}
int CBondSorter::CompareRecordDirectly(const BrokerKeyInfo& k1,
                                       const BrokerKeyInfo& k2) {
  int ncount = m_sortinfos.size();
  if (ncount <= 0 || m_record_size <= m_record_head_size) return 0;

  int total_size = 2 * m_record_size;
  if (m_buffer == 0 || m_capcity < total_size) {
    if (m_buffer) delete[] m_buffer;
    m_buffer = new char[total_size];
    memset(m_buffer, 0, total_size);
    m_capcity = total_size;
  }

  int cmp = 0;
  BrokerKey bk1, bk2;
  for (int j = 0; j < (int)m_sortinfos.size(); j++) {
    SortInfo& si = m_sortinfos[j];
    k1.GetBrokerKey(bk1);
    k2.GetBrokerKey(bk2);
    memset(m_buffer, 0, m_capcity);
    m_sort_manager->GetRecordField(bk1, si.column_id, m_buffer, si.field_bytes,
                                   false);
    m_sort_manager->GetRecordField(bk2, si.column_id, m_buffer + m_record_size,
                                   si.field_bytes, false);
    cmp = si.comparator(m_buffer, m_buffer + m_record_size);
    cmp = si.ascend ? cmp : -cmp;
    if (cmp != 0) break;
  }
  return cmp;
}

CBondSorter::kOrderChange CBondSorter::SetSortInfo(
    const std::vector<ColumnOrder>& orders) {
  // 判断是否是反序,同序,还是重新排序
  kOrderChange order_change = kOrderChangeReorder;
  if (orders.size() == m_sortinfos.size()) {
    int same_count = 0, reverse_count = 0;
    for (int i = 0; i < (int)orders.size(); i++) {
      const ColumnOrder& co = orders[i];
      if (co.comlumn == m_sortinfos[i].column_id) {
        if (co.ascend == m_sortinfos[i].ascend)
          same_count++;
        else
          reverse_count++;
      }
    }
    if (same_count == orders.size())
      order_change = kOrderChangeSame;
    else if (reverse_count > 0 && reverse_count == orders.size())
      order_change = kOrderChangeReverse;
  }

  m_sortinfos.clear();
  int offset = m_record_head_size;
  for (int i = 0; i < (int)orders.size(); i++) {
    FieldInfo fi;
    if (!m_sort_manager->GetFieldInfo(orders[i].comlumn, fi)) continue;

    SortInfo si;
    si.column_id = orders[i].comlumn;
    si.ascend = orders[i].ascend;
    si.field_bytes = fi.field_bytes;
    si.offset = offset;
    si.comparator = m_sort_manager->GetComparator(fi.sort_type);
    si.sort_type = fi.sort_type;
    m_sortinfos.push_back(si);
    offset += si.field_bytes;
  }
  m_record_size = offset;
  return order_change;
}

void CBondSorter::SetContributorId(const char* contributorId) {
  if (!contributorId) return;
  m_contributorId = contributorId;
}

void CBondSorter::Sort(const std::vector<ColumnOrder>& orders,
                       std::vector<BrokerKeyInfo>& keys, int ncorpid,
                       bool force) {
  kOrderChange order_change = SetSortInfo(orders);
  // 反向可能会有问题,暂时重新排序
  if (order_change == kOrderChangeReverse) order_change = kOrderChangeReorder;

  if ((force || order_change == kOrderChangeReorder) &&
      m_sortinfos.size() > 0) {
    m_sort_manager->Sort(keys, m_sortinfos, ncorpid, m_record_size);
  }

  if (order_change == kOrderChangeReverse) {
    if (keys.size() > 1) std::reverse(keys.begin(), keys.end());
  }
}

void CBondSorter::Sort(const std::vector<ColumnOrder>& orders,
                       std::vector<BrokerKeyInfo>& keys, BYTE btSettlement,
                       int ncorpid, bool force) {
  kOrderChange order_change = SetSortInfo(orders);
  // 反向可能会有问题,暂时重新排序
  if (order_change == kOrderChangeReverse) order_change = kOrderChangeReorder;

  if ((force || order_change == kOrderChangeReorder) &&
      m_sortinfos.size() > 0) {
    m_sort_manager->Sort(keys, m_sortinfos, btSettlement, ncorpid,
                         m_record_size);
  }

  if (order_change == kOrderChangeReverse) {
    if (keys.size() > 1) std::reverse(keys.begin(), keys.end());
  }
}

void CBondSorter::Sort(const std::vector<ColumnOrder>& orders,
                       std::vector<BrokerKeyInfo>& keys,
                       std::string& contributorId, BYTE btPriceFilter,
                       int ncorpid, bool force) {
  kOrderChange order_change = SetSortInfo(orders);
  // 反向可能会有问题,暂时重新排序
  if (order_change == kOrderChangeReverse) order_change = kOrderChangeReorder;

  if ((force || order_change == kOrderChangeReorder) &&
      m_sortinfos.size() > 0) {
    m_sort_manager->Sort(keys, m_sortinfos, contributorId, btPriceFilter,
                         ncorpid, m_record_size);
  }

  if (order_change == kOrderChangeReverse) {
    if (keys.size() > 1) std::reverse(keys.begin(), keys.end());
  }
}

bool CBondSorter::GetCheckBool(const char* name) {
  return CBoolChecker::Get().GetCheckBool(name);
}

bool CBondSorter::GetRecordField(const BrokerKey& key, int col, char* field,
                                 int capcity) {
  return m_sort_manager->GetRecordField(key, col, field, capcity, true);
}
/*



*/

/////////////////////////////////////////////////////////////////////////////////
BondSortBuffer::BondSortBuffer()
    : m_record_size(0), m_buffer(nullptr), m_capcity(0) {}

BondSortBuffer::~BondSortBuffer() {
  if (m_buffer) delete[] m_buffer;
}

bool BondSortBuffer::AddField(int id, kCompDataType type, bool ascend,
                              FieldComparator cmp /*= nullptr*/) {
  if (type != kCompDataTypeInt && type != kCompDataTypeDouble &&
      type != kCompDataTypeString && type != kCompDataTypeTime)
    return false;
  if (FindExist(id) >= 0) return false;
  SortInfo info;
  info.sort_type = type;
  info.column_id = id;
  info.offset = m_record_size;
  info.ascend = ascend;

  FieldComparator dft_cmp = nullptr;
  switch (type) {
    case kCompDataTypeTime:
      info.field_bytes = sizeof(time_t);
      dft_cmp = TimeComparator;
      break;
    case kCompDataTypeInt:
      info.field_bytes = sizeof(int);
      dft_cmp = IntComparator;
      break;
    case kCompDataTypeDouble:
      info.field_bytes = sizeof(double);
      dft_cmp = DoubleComparator;
      break;
    case kCompDataTypeString:
      info.field_bytes = sizeof(const char**);
      dft_cmp = StringComparator;
      break;
  }
  info.comparator = cmp ? cmp : dft_cmp;
  m_sorts.emplace_back(info);
  m_record_size += info.field_bytes;
  return true;
}

void BondSortBuffer::Reset() { m_sorts.clear(); }

int BondSortBuffer::CheckSort() const {
  int nerror = 0;
  for (int i = 1; i < (int)m_indexes.size(); i++) {
    int cmp = CompRecord(m_indexes[i - 1], m_indexes[i]);
    if (cmp > 0) nerror++;
  }
  return nerror;
}

void BondSortBuffer::Prepare(int count) {
  int capcity = m_record_size * count;
  if (m_buffer == nullptr || m_capcity < capcity) {
    if (m_buffer != nullptr) delete[] m_buffer;
    m_buffer = new char[capcity];
    m_capcity = capcity;
  }
}

void BondSortBuffer::Sort(vector<int>& bonds, FieldReader* reader) {
  if (bonds.size() <= 1) return;

  Prepare(bonds.size());
  m_str_page.Reset();
  m_indexes.clear();

  int offset = 0;
  m_indexes.clear();
  m_indexes.reserve(bonds.size());

  // 采集数据
  int slen = 0;
  char* record = m_buffer;
  const char* pstr = nullptr;
  char svalue[256] = {0};
  for (int i = 0; i < (int)bonds.size(); i++) {
    record = m_buffer + offset;
    m_indexes.push_back(INDEX(bonds[i], offset));
    for (int c = 0; c < (int)m_sorts.size(); c++) {
      const SortInfo& info = m_sorts[c];
      kCompDataType type = (kCompDataType)info.sort_type;
      switch (type) {
        case kCompDataTypeString:
          slen = reader->GetString(bonds[i], info.column_id, svalue,
                                   _countof(svalue));
          pstr = m_str_page.AddString(svalue, slen);
          memcpy(record + info.offset, &pstr, sizeof(const char*));
          break;
        case kCompDataTypeDouble:
          *((double*)(record + info.offset)) =
              reader->GetDouble(bonds[i], info.column_id);
          break;
        case kCompDataTypeInt:
          *((int*)(record + info.offset)) =
              reader->GetInt(bonds[i], info.column_id);
          break;
        case kCompDataTypeTime:
          *((time_t*)(record + info.offset)) =
              reader->GetTime(bonds[i], info.column_id);
          break;
      }
    }
    offset += m_record_size;
  }
  BASSERTS(offset == m_record_size * bonds.size() && offset <= m_capcity, "");

  // 排序并收集结果
  if (m_sorts.size() == 1) {
    const SortInfo& si = m_sorts[0];
    if (si.ascend)
      std::sort(m_indexes.begin(), m_indexes.end(),
                OneColumnAscendComp(m_buffer, si.offset, si.comparator));
    else
      std::sort(m_indexes.begin(), m_indexes.end(),
                OneColumnDescentComp(m_buffer, si.offset, si.comparator));
  } else
    std::sort(m_indexes.begin(), m_indexes.end(), MultiColComp(this));
  bonds.clear();
  for (int i = 0; i < (int)m_indexes.size(); i++)
    bonds.push_back(m_indexes[i].index);
}

int BondSortBuffer::CompRecord(const INDEX& k1, const INDEX& k2) const {
  int cmp = 0;
  int ncount = m_sorts.size();
  for (int i = 0; i < ncount; i++) {
    const SortInfo& si = m_sorts[i];
    int cmp = si.comparator(m_buffer + k1.offset + si.offset,
                            m_buffer + k2.offset + si.offset);
    cmp = si.ascend ? cmp : -cmp;
    if (cmp != 0) return cmp;
  }
  return cmp;
}

int BondSortBuffer::FindExist(int id) const {
  for (int i = 0; i < (int)m_sorts.size(); i++) {
    if (m_sorts[i].column_id == id) return i;
  }
  return -1;
}
